Ответ
Генераторы в PHP — это специальные функции, которые позволяют итерироваться по набору данных, не создавая весь набор в памяти сразу. Вместо ключевого слова return используется yield. При каждом вызове yield функция приостанавливает своё выполнение и возвращает текущее значение. При следующей итерации выполнение возобновляется с того же места.
Ключевая польза: Экономия оперативной памяти при работе с большими наборами данных (логи, большие файлы, объёмные результаты запросов из БД).
Сравним два подхода:
// ПЛОХО: Функция возвращает массив из миллиона чисел, загружая их все в память.
function getMillionNumbers(): array
{
$numbers = [];
for ($i = 0; $i < 1_000_000; $i++) {
$numbers[] = $i;
}
return $numbers; // Массив из 1М элементов создан в памяти
}
foreach (getMillionNumbers() as $number) {
// В начале цикла массив уже целиком в памяти.
if ($number > 100) break; // Но мы использовали только 101 элемент!
}
// Пиковое использование памяти: ~130 МБ
// ХОРОШО: Генератор возвращает значения по одному.
function generateMillionNumbers(): Generator
{
for ($i = 0; $i < 1_000_000; $i++) {
yield $i; // Возвращает $i и приостанавливается
}
}
foreach (generateMillionNumbers() as $number) {
// На каждой итерации в памяти только текущее значение $i.
if ($number > 100) break;
}
// Пиковое использование памяти: ~1 МБ
Практический пример: Чтение большого файла построчно.
function readLargeFile(string $filename): Generator
{
$handle = fopen($filename, 'r');
if (!$handle) {
throw new RuntimeException("Could not open file: {$filename}");
}
try {
while (($line = fgets($handle)) !== false) {
yield trim($line); // Отдаём строку по одной
}
} finally {
fclose($handle); // Гарантированное закрытие файла
}
}
// Использование
foreach (readLargeFile('huge_log.txt') as $lineNumber => $lineContent) {
// $lineNumber автоматически инкрементируется с каждым yield
echo "Line {$lineNumber}: {$lineContent}" . PHP_EOL;
// Файл никогда не загружается в память целиком.
}
Ключевые особенности генераторов в PHP:
- Функция-генератор возвращает объект внутреннего класса
Generator, который реализует интерфейсыIteratorиTraversable. yieldможет возвращать ключ-значение:yield $key => $value;.- Можно делегировать другой генератор с помощью
yield from(аналогawaitв некоторых других языках). - Начиная с PHP 7.0, генератор может возвращать финальное значение с помощью
return, которое можно получить через$generator->getReturn().
Генераторы — это мощный инструмент для написания эффективного по памяти кода, особенно в контексте обработки потоков данных или реализации ленивых вычислений.