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

(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('Step must be +ve');
        }

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

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