Знакомство с генераторами
(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(1, 9, 2) as $number) {
echo "$number ";
}
echo "\n";
echo 'Нечётные однозначные числа с помощью xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
echo "$number ";
}
?>
Результат выполнения приведённого примера:
Нечётные однозначные числа с помощью range(): 1 3 5 7 9
Нечётные однозначные числа с помощью xrange(): 1 3 5 7 9
Когда функция генератор вызывается, она вернёт объект встроенного
класса Generator. Этот объект реализует интерфейс
Iterator, станет однонаправленным объектом итератора
и предоставит методы, с помощью которых можно управлять его состоянием, включая
передачу в него и возвращения из него значений.