Что такое генераторы в PHP
При вождении автомобиля – скорость это далеко не все. Но в WEB все решает скорость. Чем быстрее ваше приложение, тем лучше пользовательский опыт. Хорошо, эта статья о генераторах в PHP, так почему же мы говорим о скорости? Как вы увидите вскоре, генераторы привносят большие изменения по части скорости и потреблении памяти приложением.
Что такое PHP генераторы?
Добавленные в PHP в версии 5.5, генераторы представляют собой функции, обеспечивающие простой механизм для циклической обработки данных, без необходимости создавать массив данных в памяти. Все еще не понимаете о чем речь? Тогда давайте посмотрим на PHP генераторы в действии.
Создаем файл generator_test.php со следующим содержанием:
<?php
function getRange( $max = 10 ) {
$array = [];
for( $i = 0; $i < $max; $i++ ) {
$array[] = $i;
}
return $array;
}
foreach (getRange(15) as $range) {
echo "Данные {$range} <br>";
}
?>
Затем в папке где у нас лежит этот файл открываем консоль и пишем следующее
php -S localhost:8000
Дальше открываем браузер и идем по следующему адресу:
http://localhost:8000/generator_test.php
Результат будет такой:
Данные 1
Данные 2
….
Данные 15
Код выше достаточно прост. Однако, давайте сделаем небольшое изменение в нем:
<?php
foreach (getRange(PHP_INT_MAX) as $range) {
echo "Данные {$range} <br>";
}
?>
Теперь диапазон генерируемых чисел находится в пределах от 0 до константы PHP_INT_MAX, которая представляет собой наибольшее целое число, которое способен представить интерпретатор PHP. После этого опять идем в браузер и обновляем страницу. Однако на этот раз, вместо обычного текста получаем сообщение о том, что превышен объем доступной памяти, вследствие чего работа скрипта была аварийно завершена.
Что за досада – у PHP закончилась память! Первое что приходит на ум – это редактировать настройку memory_limit в php.ini. Но давайте спросим себя – действительно ли это так эффективно? Неужели мы хотим, чтобы какой-то единственный скрипт занимал всю доступную память?
Используем генераторы
Давайте напишем ту же самую функцию, что и выше, вызовем ее с тем же значением PHP_INT_MAX и запустим снова. Но в этот раз мы создадим функцию-генератор.
<?php
function getRange( $max = 10 ) {
for( $i = 1; $i < $max; $i++ ) {
yield $i;
}
}
foreach (getRange(PHP_INT_MAX) as $range) {
echo "Данные {$range} <br>";
}
?>
Определяя функцию getRange на этот раз, мы всего лишь проходим по значениям и генерируем вывод. Ключевое слово yield похоже на инструкцию return тем, что возвращает значение из функции, но единственное отличие заключается в том, что yield возвращает значение только тогда, когда это необходимо и не пытается вместить весь массив данных в память за один раз. Перейдя к браузеру, вы должны увидеть данные, отображаемые на странице. Обратите внимание на тот факт, что генераторы в PHP могут быть использованы только лишь из функции.
Зачем нужны генераторы?
Время от времени возникают такие задачи, когда нам необходимо обработать большие объемы данных (например, файлы логов), выполнить вычисления на больших выборках из базы и т.д. И мы отнюдь не хотим, чтобы эти операции занимали всю доступную память, так мы должны стараться сохранять память насколько это возможно. Данные не обязательно должны быть большими – PHP генераторы эффективны вне зависимости от размера данных. И не забывайте, что наша цель – сделать приложение быстрым и при этом таким, чтобы оно потребляло как можно меньше памяти.
Возврат ключей
Бывают случаи, когда нам необходимо возвращать не просто значение, а пару ключ-значение. При использовании генераторов, мы можем генерировать пары ключ-значение следующим образом.
<?php
function getRange( $max = 10 ) {
for( $i = 0; $i < $max; $i++ ) {
$value = $i * mt_rand();
yield $i => $value;
}
}
?>
Использовать данную функцию мы можем также как и простой массив:
<?php
foreach (getRange(PHP_INT_MAX) as $key => $value ) {
echo "Ключ {$key} имеет значение {$value}";
}
?>
Отсылка значений генераторам
Генераторы также могут принимать значения. Под этим подразумевается, что генераторы позволяют нам вставлять значения, которое может представлять собой подобие команды или еще что-то. Например, мы можем отправить значение в наш генератор, которое сигнализирует о необходимости остановки исполнения или изменения выходных данных. Далее пример кода:
<?php
function getRange( $max = 10 ) {
for( $i = 1; $i < $max; $i++ ) {
$inject = yield $i;
if( $inject === 'stop' ) return;
}
}
$generator = getRange(PHP_INT_MAX);
foreach( $generator as $range ) {
if($range === 10000) {
// посылаем сообщение генератору
$generator -> send('stop');
}
print "Значение {$range} <br>";
}
?>
Отмечу, что использование инструкции return в функции-генераторе приведет к немедленному выходу из этой функции.
В заключении отмечу, что генераторы предлагают значительное улучшение производительности, которое мы не можем игнорировать. Большую часть времени нам не нужно иметь мощные сервера для выполнения нашего кода - нам просто необходимо сделать небольшой рефакторинг. И генераторы очень полезный инструмент, который мы должны использовать более часто, при этом, не злоупотребляя им.
Кстати, о генераторах я подробно рассказываю в моем курсе PHP и MySQL с Нуля до Гуру 2.0. Там есть и примеры и задания, которые помогут лучше усвоить материал.
-
- Михаил Русаков
Комментарии (2):
нихера не понял
Ответить
генераторы в отличии от массивов ОЗУ не кушают и код выполняется в разы быстрее. НО генератор можно записать только 1 раз + перезаписать данные генератора нет возможности + считать данные тоже можно только 1 раз. Наведите плз пример кто шарит - как запихнуть результат выборки с базы данных в генератор, (результат запроса в базу данных).
Ответить
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.