Что такое генераторы (Generators) в PHP?php-30

Генераторы — это специальные функции в PHP, которые позволяют итерировать по набору данных без необходимости создания всего массива в памяти. Они генерируют значения "на лету", что делает их исключительно полезными для работы с большими наборами данных или бесконечными последовательностями.

Основные особенности генераторов

  1. Ленивые вычисления: Значения вычисляются только когда они действительно нужны
  2. Экономия памяти: Не загружают все данные в память сразу
  3. Синтаксический сахар: Упрощают реализацию итераторов

Базовый пример генератора

<?php
function generateNumbers($limit) {
    for ($i = 1; $i <= $limit; $i++) {
        // yield возвращает значение и приостанавливает функцию
        yield $i;
    }
}

foreach (generateNumbers(1000000) as $number) {
    echo $number . "\n";
}

В этом примере не создается массив из миллиона чисел — каждое число генерируется по требованию.

Ключевые преимущества

  1. Экономия памяти:

    • Обычный подход: 1 000 000 элементов × 16 байт = ```16MB
    • Генератор: несколько десятков байт
  2. Бесконечные последовательности:

<?php
function infiniteSequence() {
    $i = 0;
    while (true) {
        yield $i++;
    }
}
  1. Возвращение пар ключ-значение:
<?php
function keyValueGenerator() {
    yield 'a' => 1;
    yield 'b' => 2;
}

Отличия от обычных функций

Характеристика Обычная функция Генератор
Возврат значения return yield
Состояние Теряется после вызова Сохраняется между вызовами
Память Хранит все данные Хранит только текущее значение
Возвращаемый тип Любой \Generator

Продвинутое использование

  1. Делегирование генерации:
<?php
function generatorA() {
    yield 1;
    yield 2;
}

function generatorB() {
    yield from generatorA(); // Делегирование
    yield 3;
}
  1. Отправка значений в генератор:
<?php
function receivingGenerator() {
    $received = yield; // Получаем значение
    yield "Получено: $received";
}

$gen = receivingGenerator();
$gen->send('Hello!'); // Отправляем значение
echo $gen->current(); // Выведет "Получено: Hello!"
  1. Обработка больших файлов:
<?php
function readLargeFile($fileName) {
    $file = fopen($fileName, 'r');

    while (!feof($file)) {
        yield fgets($file);
    }

    fclose($file);
}

foreach (readLargeFile('huge_log.txt') as $line) {
    // Обработка каждой строки
}

Ограничения генераторов

  1. Нельзя использовать return для возвращения значения (до PHP 7.0)
  2. Нельзя использовать yield внутри конструктора класса
  3. Однонаправленность — нельзя перематывать назад

Резюмируем:

  • Генераторы идеальны для обработки больших данных
  • Экономят память за счет ленивой загрузки
  • Сохраняют состояние между вызовами
  • Могут делегировать выполнение другим генераторам
  • Позволяют двустороннюю коммуникацию через send()