Новичкам в PHP приходится работать с большими наборами данных или массивами. Типичная проблема  —  страшная ошибка нехватки памяти:

Fatal error: Allowed memory size of xxxxxx bytes exhausted (tried to allocate xxxxx bytes) in your_script.php on line xx

Здесь PHP-скриптом превышен лимит памяти. Чтобы устранить эту ошибку, в PHP 5.5 представили отличное решение  —  генераторы. Они позволяют перебирать наборы данных, не загружая все в память. Это эффектно и эффективно.

Что такое «генераторы»?

Генераторы  —  это способ пройтись по набору данных, не создавая полного массива в памяти. То есть на проработку больших наборов данных расходуется меньше памяти.

Принцип работы генераторов

При использовании генератора им не загружается в память весь набор данных, а обрабатывается по одной их части. В PHP это достигается с помощью ключевого слова yield.

Применение генераторов: пошаговое руководство

1. Базовый синтаксис генератора

Чтобы создать генератор, оператором yield определяется функция:

function numberGenerator($start = 1, $end = 10) {
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}

//И для его использования:
foreach (numberGenerator() as $number) {
echo $number . "<br>";
}

2. Преобразование обычной функции в генератор

Рассмотрим функцию, в которой возвращается массив:

function getNumbers($start = 1, $end = 10) {
$numbers = [];
for ($i = $start; $i <= $end; $i++) {
$numbers[] = $i;
}
return $numbers;
}

Использование этой функции с большим значением $end чревато проблемами с памятью. Преобразуем ее в генератор:

function getNumbersGenerator($start = 1, $end = 10) {
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}

3. Получение пар «ключ  —  значение»

С помощью yield также получаем пары ключ  —  значение:

function keyValueGenerator() {
yield 'a' => 1;
yield 'b' => 2;
yield 'c' => 3;
}

Обратная отправка данных генераторам

Генераторами данные не только выводятся, с помощью метода send во время выполнения ими также принимаются входные данные:

function receiveDataGenerator() {
while (true) {
$data = yield;
if ($data === 'stop') {
return; // Выход из генератора
}
echo "Received: $data<br>";
}
}

$generator = receiveDataGenerator();
$generator->send('Hello');
$generator->send('World');
$generator->send('stop');

Возвращение значений из генераторов

Генераторами, используя yield, не только получают значения, но с помощью return возвращают конечное значение:

function countdownGenerator($start) {
for ($i = $start; $i >= 0; $i--) {
yield $i;
}
return 'Blastoff!';
}

$gen = countdownGenerator(5);
foreach ($gen as $value) {
echo "$value<br>";
}
echo $gen->getReturn(); // Выводится «'Blastoff!'»

Примеры практического использования

Генераторы особенно полезны в сценариях обработки больших файлов или потоков данных, например при построчном считывании большого файла:

function readFileLineByLine($filename) {
$file = fopen($filename, 'r');
while (!feof($file)) {
yield fgets($file);
}
fclose($file);
}

foreach (readFileLineByLine('large_file.txt') as $line) {
echo $line . "<br>";
}

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

По мере освоения PHP и включения генераторов в инструментарий, ваши возможности как разработчика, несомненно, расширятся.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Cleyton Bonamigo: Unlocking the Power of PHP Generators

Предыдущая статьяViewModel. События как состояние  —  это антипаттерн
Следующая статья5 типичных ошибок веб-разработчиков