Генераторы предоставляют простой способ реализации простых итераторов без накладных расходов или сложности реализации класса, реализующего интерфейс Iterator .

Генератор позволяет вам писать код, который использует foreach для перебора набора данных без необходимости построения массива в памяти, что может привести к превышению лимита памяти или потребовать значительного времени обработки для генерации. Вместо этого вы можете написать функцию генератора, которая аналогична обычной функции , за исключением того, что вместо однократного возврата генератор может возвращать столько раз, сколько необходимо, чтобы предоставить значения для итерации.

Простым примером этого является повторная реализация функции range() в качестве генератора. Стандартная функция range() должна генерировать массив с каждым значением в нем и возвращать его, что может привести к большим массивам: например, вызов range(0, 1000000) приведет к использованию более 100 МБ памяти.

В качестве альтернативы мы можем реализовать xrange() генератор, которому всегда будет достаточно памяти только для создания объекта Iterator и внутреннего отслеживания текущего состояния генератора, который оказывается менее 1 килобайта.

Пример #1 Реализация range() в качестве генератора

<?php
function xrange($start, $limit, $step = 1) {
    if ($start <= $limit) {
        if ($step <= 0) {
            throw new LogicException('Step must be positive');
        }

        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('Step must be negative');
        }

        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}

/*
 * Note that both range() and xrange() result in the same
 * output below.
 */

echo 'Single digit odd numbers from range():  ';
foreach (range(1, 9, 2) as $number) {
    echo "$number ";
}
echo "\n";

echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
    echo "$number ";
}
?>

Приведенный выше пример выведет:

Одноразрядные нечетные числа из диапазона(): 1 3 5 7 9
Одноразрядные нечетные числа из xrange(): 1 3 5 7 9

Объекты - генераторы

При вызове функции генератора возвращается новый объект внутреннего класса Generator . Этот объект реализует интерфейс Iterator почти так же, как и объект итератора, работающий только в прямом направлении, и предоставляет методы, которые можно вызывать для управления состоянием генератора, включая отправку значений в него и возврат значений из него.