Знакомство с генераторами

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

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

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

Наглядным примером вышесказанного может послужить использование функции 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('Шаг должен быть положительным');
        }

        for (
$i $start$i <= $limit$i += $step) {
            yield 
$i;
        }
    } else {
        if (
$step >= 0) {
            throw new 
LogicException('Шаг должен быть отрицательным');
        }

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

/* Обратите внимание, что и range() и xrange() дадут один и тот же вывод */

echo 'Нечетные однозначные числа с помощью range():  ';
foreach (
range(192) as $number) {
    echo 
"$number ";
}
echo 
"\n";

echo 
'Нечетные однозначные числа с помощью xrange(): ';
foreach (
xrange(192) as $number) {
    echo 
"$number ";
}
?>

Результат выполнения данного примера:

Нечетные однозначные числа с помощью range():  1 3 5 7 9 
Нечетные однозначные числа с помощью xrange(): 1 3 5 7 9 

Объект Generator

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