Что такое yield
?
В yield
ключевом слове возвращает данные функции генератора:
Сердцем функции генератора является ключевое слово yield. В своей простейшей форме оператор yield очень похож на оператор return, за исключением того, что вместо остановки выполнения функции и возврата yield вместо этого предоставляет значение для кода, зацикливающегося над генератором, и приостанавливает выполнение функции генератора.
Что такое функция генератора?
Функция генератора - фактически более компактный и эффективный способ написать Итератор . Это позволяет вам определить функцию (вашу xrange
), которая будет вычислять и возвращать значения, пока вы зацикливаетесь на ней :
foreach (xrange(1, 10) as $key => $value) {
echo "$key => $value", PHP_EOL;
}
Это создаст следующий вывод:
0 => 1
1 => 2
…
9 => 10
Вы также можете управлять $key
в foreach
с помощью
yield $someKey => $someValue;
В функции генератора, $someKey
является то , что вы хотите появляться $key
и $someValue
быть значение $val
. В примере вопроса это $i
.
В чем разница с обычными функциями?
Теперь вы можете задаться вопросом, почему мы не просто используем нативную range
функцию PHP для достижения этого результата. И ты прав. Вывод будет таким же. Разница в том, как мы туда попали.
Когда мы используем range
PHP, будет выполнять его, создать весь массив чисел в памяти и return
что весь массив в foreach
цикл , который будет идти по нему и выводить значение. Другими словами, foreach
операция будет работать с самим массивом. range
Функция и foreach
только «говорить» один раз. Думайте об этом как о получении посылки по почте. Курьер доставит вам посылку и уйдет. А затем вы разворачиваете весь пакет, вынимая все, что там есть.
Когда мы используем функцию генератора, PHP входит в функцию и выполняет ее, пока она не встретит конец или yield
ключевое слово. Когда он встречает a yield
, он затем возвращает то, что является значением в то время, во внешний цикл. Затем он возвращается в функцию генератора и продолжает с того места, где он уступил. Так как ваш xrange
держит for
цикл, он будет выполняться и давать, пока не $max
будет достигнут. Думайте об этом как foreach
о генераторе, играющем в пинг-понг.
Зачем мне это нужно?
Очевидно, что генераторы можно использовать для обхода ограничений памяти. В зависимости от вашей среды выполнение range(1, 1000000)
сценария приведет к фатальному сценарию, тогда как то же самое с генератором будет работать нормально. Или, как говорит Википедия:
Поскольку генераторы вычисляют свои полученные значения только по требованию, они полезны для представления последовательностей, которые было бы дорого или невозможно вычислить сразу. К ним относятся, например, бесконечные последовательности и потоки данных в реальном времени.
Генераторы также должны быть довольно быстрыми. Но имейте в виду, что когда мы говорим о быстром, мы обычно говорим в очень небольших количествах. Поэтому, прежде чем вы сейчас запустите и измените весь свой код на использование генераторов, сделайте тест, чтобы увидеть, где это имеет смысл.
Другой вариант использования для генераторов - асинхронные сопрограммы. yield
Ключевое слово не возвращает только значение , но и принимает их. Подробнее об этом см. В двух великолепных сообщениях в блогах, ссылки на которые приведены ниже.
С каких пор я могу использовать yield
?
Генераторы были введены в PHP 5.5 . Попытка использовать yield
до этой версии приведет к различным ошибкам синтаксического анализа, в зависимости от кода, который следует за ключевым словом. Поэтому, если вы получили ошибку разбора этого кода, обновите ваш PHP.
Источники и дальнейшее чтение:
yeild
, скажем, такого решения, как это: ideone.com/xgqevMreturn range(1,100000000)
иfor ($i=0; $i<100000000; $i++) yield $i
Эта функция использует yield:
почти такой же, как этот без:
Единственное отличие состоит в том, что
a()
возвращает генератор иb()
просто простой массив. Вы можете повторить и то и другое.Кроме того, первый не выделяет полный массив и поэтому требует меньше памяти.
источник
простой пример
вывод
расширенный пример
вывод
источник
yield
Ключевое слово служит для определения «генераторов» в PHP 5.5. Хорошо, тогда что такое генератор ?С php.net:
Отсюда: генераторы = генераторы, другие функции (просто простые функции) = функции.
Итак, они полезны, когда:
вам нужно делать простые вещи (или простые вещи);
генератор действительно намного проще, чем реализация интерфейса Iterator. с другой стороны, конечно, что генераторы менее функциональны. сравните их .
вам нужно генерировать большие объемы данных - экономя память;
фактически для экономии памяти мы можем просто генерировать необходимые данные с помощью функций для каждой итерации цикла, а после итерации использовать мусор. Итак, основные моменты - понятный код и, возможно, производительность. посмотрим, что лучше для ваших нужд.
вам нужно сгенерировать последовательность, которая зависит от промежуточных значений;
это расширение предыдущей мысли. генераторы могут сделать вещи проще по сравнению с функциями. проверьте пример Фибоначчи и попробуйте составить последовательность без генератора. Также генераторы могут работать быстрее в этом случае, по крайней мере, из-за хранения промежуточных значений в локальных переменных;
вам нужно улучшить производительность.
в некоторых случаях они могут работать быстрее, чем функции (см. предыдущее преимущество);
источник
С
yield
его помощью можно легко описать точки останова между несколькими задачами в одной функции. Вот и все, в этом нет ничего особенного.Если task1 и task2 тесно связаны, но вам нужна точка останова между ними, чтобы сделать что-то еще:
тогда генераторы - лучшее решение, потому что вам не нужно разбивать ваш код на множество замыканий или смешивать его с другим кодом, или использовать обратные вызовы и т. д. Вы просто используете,
yield
чтобы добавить точку останова, и вы можете продолжить с этого Точка останова, если вы готовы.Добавить точку останова без генераторов:
Добавить точку останова с генераторами
примечание: легко ошибиться с генераторами, поэтому всегда пишите модульные тесты, прежде чем применять их! note2: Использование генераторов в бесконечном цикле похоже на написание замыкания бесконечной длины ...
источник
Ни один из ответов выше не показывает конкретный пример использования массивных массивов, заполненных нечисловыми элементами. Вот пример использования массива, созданного
explode()
в большом файле .txt (в моем случае - 262 МБ):Выход был:
Теперь сравните это с похожим сценарием, используя
yield
ключевое слово:Выход для этого скрипта был:
Очевидно, что экономия использования памяти была значительной (ΔMemoryUsage -----> ~ 270,5 МБ в первом примере, ~ 450 В во втором примере).
источник
Интересный аспект, который стоит обсудить здесь, дает ссылки . Каждый раз, когда нам нужно изменить параметр таким образом, чтобы он отражался вне функции, мы должны передавать этот параметр по ссылке. Чтобы применить это к генераторам, мы просто добавляем амперсанд
&
к имени генератора и к переменной, используемой в итерации:Приведенный выше пример показывает, как изменение повторяющихся значений в
foreach
цикле изменяет$from
переменную в генераторе. Это потому , что$from
это дало в качестве ссылки в связи с амперсандом перед именем генератора. Из-за этого$value
переменная вforeach
цикле является ссылкой на$from
переменную в функции генератора.источник
Приведенный ниже код иллюстрирует, как использование генератора возвращает результат до завершения, в отличие от традиционного подхода без генератора, который возвращает полный массив после полной итерации. В приведенном ниже генераторе значения возвращаются, когда они готовы, не нужно ждать полного заполнения массива:
источник