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

(PHP 5 >= 5.5.0, PHP 7)

Генераторы предоставляют лёгкий способ реализации простых итераторов без использования дополнительных ресурсов или сложностей, связанных с реализацией класса, реализующего интерфейс 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, станет однонаправленным объектом итератора и предоставит методы, с помощью которых можно управлять его состоянием, включая передачу в него и возвращения из него значений.