Генераторы в PHP. Генерация случайных строк в PHP Generator generate в php как работает

А теперь берем уже готовую функцию генерации пароля и пишем скрипт для восстановления или создания нового пароля для пользователей вашего сайта.

Скрипт восстановления пароля

Как обычно пишется скрипт?

Как всегда составляется поэтапная схема, что мы должны сделать по шагам. Все происходит в одном файле, reminder.php

1. Запускаем скрипт, только при наличии определенной переменной, например $action;

2. Для запуска процесса генерации пароля, пользователь указывает email адрес $_POST[`ema‘l`]; Для упрощения кода присвоим данное значение переменной $email.

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

4. Ищем в базе данных, в нашем случае в таблице users пользователя с таким почтовым адресом. Если нет, выдаем ошибку, что такого адреса в базе нет, и прекращаем работу скрипта.

5. Пользователь с таким адресом в базе есть, идем дальше и запускаем функцию генерации нового пароля. Также по адресу емайл получаем из базы уникальный id пользователя и пишем в переменную $id;

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

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

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

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

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

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

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

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

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

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

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

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

rulerz->satisfies($ebook, $rule)) { $filteredEbooks = $ebook; } } return $filteredEbooks; }

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

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

rulerz->satisfies($ebook, $rule)) { yield $ebook; } } }

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

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

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

rulerz->filter($ebooks, $rule); }

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

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

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

db->prepare("SELECT * FROM ebook_catalog"); $stmt->execute(); $stmt->setFetchMode(\PDO::FETCH_ASSOC); foreach ($stmt as $data) { $ebooks = $this->hydrateEbook($data); } // and from Elasticsearch (findAll uses ES scan/scroll) $cursor = $this->esClient->findAll(); foreach ($cursor as $data) { $ebooks = $this->hydrateEbook($data); } return $ebooks; }

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

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

db->prepare("SELECT * FROM ebook_catalog"); $stmt->execute(); $stmt->setFetchMode(\PDO::FETCH_ASSOC); foreach ($stmt as $data) { yield $this->hydrateEbook($data); } // and from Elasticsearch (findAll uses ES scan/scroll) $cursor = $this->esClient->findAll(); foreach ($cursor as $data) { yield $this->hydrateEbook($data); } }

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

getEbooksFromDatabase(); yield from $this->getEbooksFromEs(); } private function getEbooksFromDatabase() { $stmt = $this->db->prepare("SELECT * FROM ebook_catalog"); $stmt->execute(); $stmt->setFetchMode(\PDO::FETCH_ASSOC); foreach ($stmt as $data) { yield $this->hydrateEbook($data); } } private function getEbooksFromEs() { // and from Elasticsearch (findAll uses ES scan/scroll) $cursor = $this->esClient->findAll(); foreach ($cursor as $data) { yield $this->hydrateEbook($data); } }

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

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

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

getEbooksFromCSV(); yield from $this->getEbooksFromDatabase(); }

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

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

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

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

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

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

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

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

Привет всем, сегодня я расскажу Вам о генерации случайных чисел в PHP . Благодаря лишь одной функции мы можем получить случайное число из заданного диапазона, что является довольно полезной задачей. Например, вы сможете вывести случайные записи на сайте, также можно реализовать капчу. Называется данная функция mt_rand , в качестве параметров Вы можете ничего не указывать, и тогда данная функция будет возвращать случайное число от нуля до максимально поддерживаемого значения. Наврятли Вам понадобится данная функция без использования параметров, но все же для того чтобы Вы знали о необязательной возможности их указывать я Вам это пояснил. Два параметра, которые можно задать в данной функции, это минимальное значение и максимальное значение, а Вам будет возвращено число из этого диапазона значений. Осталось лишь показать Вам пример ее использования.

echo mt_rand(). "
" ;

echo mt_rand(-5 , 7 ). "
" ;

echo mt_rand(3 , 20 ). "
" ;

?>

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