Меню

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

Что такое генераторы в PHP

При вождении автомобиля – скорость это далеко не все. Но в WEB все решает скорость. Чем быстрее ваше приложение, тем лучше пользовательский опыт. Хорошо, эта статья о генераторах в PHP, так почему же мы говорим о скорости? Как вы увидите вскоре, генераторы привносят большие изменения по части скорости и потреблении памяти приложением.

Что такое PHP генераторы?

Добавленные в PHP в версии 5.5, генераторы представляют собой функции, обеспечивающие простой механизм для циклической обработки данных, без необходимости создавать массив данных в памяти. Все еще не понимаете о чем речь? Тогда давайте посмотрим на PHP генераторы в действии.

Создаем файл generator_test.php со следующим содержанием:

Затем в папке где у нас лежит этот файл открываем консоль и пишем следующее

Дальше открываем браузер и идем по следующему адресу:

Данные 1
Данные 2
….
Данные 15

Код выше достаточно прост. Однако, давайте сделаем небольшое изменение в нем:

Теперь диапазон генерируемых чисел находится в пределах от 0 до константы PHP_INT_MAX, которая представляет собой наибольшее целое число, которое способен представить интерпретатор PHP. После этого опять идем в браузер и обновляем страницу. Однако на этот раз, вместо обычного текста получаем сообщение о том, что превышен объем доступной памяти, вследствие чего работа скрипта была аварийно завершена.

Что за досада – у PHP закончилась память! Первое что приходит на ум – это редактировать настройку memory_limit в php.ini. Но давайте спросим себя – действительно ли это так эффективно? Неужели мы хотим, чтобы какой-то единственный скрипт занимал всю доступную память?

Используем генераторы

Давайте напишем ту же самую функцию, что и выше, вызовем ее с тем же значением PHP_INT_MAX и запустим снова. Но в этот раз мы создадим функцию-генератор.

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

Зачем нужны генераторы?

Время от времени возникают такие задачи, когда нам необходимо обработать большие объемы данных (например, файлы логов), выполнить вычисления на больших выборках из базы и т.д. И мы отнюдь не хотим, чтобы эти операции занимали всю доступную память, так мы должны стараться сохранять память насколько это возможно. Данные не обязательно должны быть большими – PHP генераторы эффективны вне зависимости от размера данных. И не забывайте, что наша цель – сделать приложение быстрым и при этом таким, чтобы оно потребляло как можно меньше памяти.

Возврат ключей

Бывают случаи, когда нам необходимо возвращать не просто значение, а пару ключ-значение. При использовании генераторов, мы можем генерировать пары ключ-значение следующим образом.

Использовать данную функцию мы можем также как и простой массив:

Отсылка значений генераторам

Генераторы также могут принимать значения. Под этим подразумевается, что генераторы позволяют нам вставлять значения, которое может представлять собой подобие команды или еще что-то. Например, мы можем отправить значение в наш генератор, которое сигнализирует о необходимости остановки исполнения или изменения выходных данных. Далее пример кода:

Читайте также:  Вортекс эстина ролики ремня генератора

Отмечу, что использование инструкции return в функции-генераторе приведет к немедленному выходу из этой функции.

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

Кстати, о генераторах я подробно рассказываю в моем курсе PHP и MySQL с Нуля до Гуру 2.0. Там есть и примеры и задания, которые помогут лучше усвоить материал.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  • BB-код ссылки для форумов (например, можете поставить её в подписи):
  • Комментарии ( 2 ):

    генераторы в отличии от массивов ОЗУ не кушают и код выполняется в разы быстрее. НО генератор можно записать только 1 раз + перезаписать данные генератора нет возможности + считать данные тоже можно только 1 раз. Наведите плз пример кто шарит — как запихнуть результат выборки с базы данных в генератор, (результат запроса в базу данных).

    Для добавления комментариев надо войти в систему.
    Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

    Copyright © 2010-2021 Русаков Михаил Юрьевич. Все права защищены.

    Источник

    Использование php-генераторов

    Несмотря на то, что php-генераторы доступны с php 5.5.0, они все еще почти не используются. Более того, большинство разработчиков, которых я знаю, понимают, как работают генераторы, но не видят, когда они могут быть полезны в реальной жизни.

    Да, генераторы определенно смотрятся хорошо, но знаете. Я не понимаю, где они могут быть полезными для меня, разве что для расчета последовательности Фибоначчи.

    И они не ошибаются, ведь даже примеры в php -документации слишком упрощены. Они только объясняют, как эффективно реализовать range или итерировать по строкам файла .

    Но даже с этих простых пример мы можем понять ключевые преимущества использования генераторов : они просто упрощают итераторы.

    Генераторы позволяют вам написать код, который использует foreach для итерации множества данных без необходимости выделения памяти под массив.

    Держа этот факт в памяти, я попытаюсь объяснить, почему генераторы насколько здорово помогли мне решить задачи над которыми я работал в компании.

    Читайте также:  Генератор постройки в симс 4

    Сначала немного контекста

    Я работаю в TEA. В основном, мы разрабатываем экосистему для электронных книжек. Это покрывает весь путь от получения файлов нужного формата от издателей до размещения их на e-commerce сайте и предоставления конечному потребителю возможности читать онлайн (используя браузер, написанный @johanpoirier) или с электронной книги.

    Для возможности продавать книги и отображения релевантной информации потребителям, нам нужно много метаданных продуктов (заголовок, формат, цена, издатели, автор(ы), . ).

    В большинстве примеров кода дальше я буду называть эти метаданные $ebooks.

    Итерация по крупному множеству данных

    Для первого примера использования, давайте предположим, что у меня есть большая коллекция книг и я хочу отфильтровать те, которые можно читать у веб-просмотрщике.

    По традиции я должен был бы написать что-то вроде:

    Проблему легко увидеть: чем больше книг, тем больше нужно памяти для $filteredEbooks.

    Одно из решений — создать итератор, который бы итерировал $ebooks и возвращал подходящие. Но для этого нам нужно было бы создать новый класс, кроме того, итераторы реализируются немного утомительно. К счастью, с php 5.5.0 мы можем использовать генераторы!

    Да, рефакторинг метода getEbooksEligibleToWebReader для использования генератора очень прост: заменяем передачу значений в переменную $filteredEbooks конструкцией yield.

    Предположив, что $ebooks не массив книг , а итератор, или генератор (даже лучше!), потребление памяти теперь будет константой, не важно, сколько книг нужно вернуть, и мы уверены, что книги будут искаться только когда реально понадобятся.

    Бонус: RulerZ внутри использует генераторы, так что мы можем переписать метод и остаться с той же оптимизацией по выделению памяти.

    Агрегация нескольких источников данных

    Теперь рассмотрим момент получения $ebooks. Я вам не сказал, но они по факту приходят с разных источников: реляционной БД и Elasticsearch.

    Мы можем написать простой метод, агрегирующий эти два источники:

    Но еще раз, количество потребляемой памяти при использовании подобного подхода очень зависит от количества книг, хранимых в базе данных и Elasticsearch.

    Мы можем начать использовать генераторы и возвратить результат:

    Так, конечно, лучше, но у нас все равно есть проблема: наш метод getBooks выполняет слишком много работы! Мы должны разделить две ответственности (считывание данных с БД и вызов Elasticsearch ) в два метода:

    Вы могли заметить использование yield from оператора (доступен с php 7.0), который позволяет делегировать использование генераторов. Это идеально, к примеру, для агрегации нескольких источников данных, которые используют генераторы.

    yield from оператор работает с любым Traversable объектом, так что массивы и итераторы также могут быть использованы с этим оператором.

    Используя такую конструкцию, мы можем агрегировать несколько источников данных пару строками кода:

    Сложная ленивая (по требованию) гидрация записей БД

    Другой вариант использования генераторов — реализация ленивой гидрации, которая может обрабатывать связи.

    Мне нужно было импортировать сотни тысяч заказов с давней БД в нашу систему, каждый заказ содержал несколько пунктов.

    Наличие заказов и «пунктов заказов» было предпосылкой к тому, что мы должны сделать. Я написал метод, который возвращает сгидрированые заказы и при этом не становится слишком медленным или прожорливым.

    Идея слегка наивная: сджойнить заказы с пунктами, и сгруппировать заказы и пункты заказов в цикле.

    Читайте также:  Качество генератора случайных чисел

    Используя генераторы, мне удалось реализовать метод, который получает заказы с БД и присоединяет соответствующие пункты заказа. Все это потребляет стабильное количество памяти. Генератор избавил от надобности держать все заказы и их пункты: текущий заказ — это все, что мне нужно, чтобы сагрегировать все данные.

    Имитация асинхронных задач

    Последнее, но тем не менее важное: генераторы так же могут быть использованы для имитации асинхронных задач. Пока я писал эту заметку, я наткнулся на пост @nikita_ppv на такую же тематику, и так как он первый реализовал генераторы в php, я просто оставлю ссылку на его пост.

    Он быстро объясняет что такое генераторы и (в деталях) как мы можем получить преимущества из-за того, что они могут быть прерваны и отправлять/принимать данные для реализации сопрограмм и даже многозадачности.

    Подводя итог

    • . упрощенные итераторы;
    • . могут возвращать неограниченные объемы данных без дополнительного потребления памяти;
    • . могут быть агрегированы с помощью делегирования генераторов;
    • . могут быть использованы для реализации многозадачности;
    • . просто прикольные!

    Источник

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

    Генераторы предоставляют лёгкий способ реализации простых итераторов без использования дополнительных ресурсов или сложностей, связанных с реализацией класса, реализующего интерфейс Iterator .

    Генератор позволяет вам писать код, использующий foreach для перебора набора данных без необходимости создания массива в памяти, что может привести к превышению лимита памяти, либо потребует довольно много времени для его создания. Вместо этого, вы можете написать функцию-генератор, которая, по сути, является обычной функцией, за исключением того, что вместо возврата единственного значения, генератор может возвращать (yield) столько раз, сколько необходимо для генерации значений, позволяющих перебрать исходный набор данных.

    Наглядным примером вышесказанного может послужить использование функции range() как генератора. Стандартная функция range() генерирует массив, состоящий из значений, и возвращает его, что может привести к генерации огромных массивов данных. Например, вызов range(0, 1000000) приведёт к использованию более 100 МБ оперативной памяти.

    В качестве альтернативы мы можем создать генератор xrange() , который использует память только для создания объекта Iterator и сохранения текущего состояния, что потребует не больше 1 килобайта памяти.

    Пример #1 Реализация range() как генератора

    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 » ;
    >
    ?>

    Результат выполнения данного примера:

    Объект Generator

    Когда функция генератор вызывается, она вернёт объект встроенного класса Generator . Этот объект реализует интерфейс Iterator , станет однонаправленным объектом итератора и предоставит методы, с помощью которых можно управлять его состоянием, включая передачу в него и возвращения из него значений.

    Источник

    Adblock
    detector