В чем разница между генератором и массивом?

Сегодня команда PHP выпустила версию PHP 5.5.0 , которая включает поддержку генераторов . Читая документацию , я заметил, что она делает именно то, что она может сделать с массивом.

Пример генератора PHP-команды :

// Only PHP 5.5 function gen_one_to_three() { for ($i = 1; $i <= 3; $i++) { // Note that $i is preserved between yields. yield $i; } } $generator = gen_one_to_three(); foreach ($generator as $value) { echo "$value\n"; } 

Результат :

 1 2 3 

Но я могу сделать то же самое, используя массивы. И я все еще могу поддерживать совместимость с более ранними версиями PHP.

Посмотрите :

 // Compatible with 4.4.9! function gen_one_to_three() { $results = array(); for ($i = 1; $i <= 3; $i++) { $results[] = $i; } return $results; } $generator = gen_one_to_three(); foreach ($generator as $value) { echo "$value\n"; } 

Поэтому возникает вопрос : какова цель существования этой новой функции? Я получил все примеры документации без использования новой функции, заменив ее массивом.

Может ли кто-нибудь дать хорошее объяснение и, возможно, пример, который не всегда бывает невозможным для более старых версий, но использование генераторов может помочь в разработке?

Разница заключается в эффективности. Например, многие языки, кроме PHP, включают в себя две функции range() , range() и xrange() . Это действительно хороший пример генераторов и почему их использовать. Давайте построим свой собственный:

 function range($start, $end) { $array = array(); for ($i = $start; $i <= $end; $i++) { $array[] = $i; } return $array; } 

Теперь это действительно прямо. Однако для больших диапазонов требуется большой объем памяти. Если бы мы попытались запустить его с $start = 0 и $end = 100000000 , у нас наверняка закончилась память!

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

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

Теперь мы используем постоянную память, но все же имеем «массив» (например, структуру), который мы можем перебирать (и использовать с другими итераторами) в том же пространстве.

Он не заменяет массив, но он обеспечивает эффективный способ избежать необходимости в памяти …

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

 function fetchFromDb($result) { while ($row = $result->fetchArray()) { $record = doSomeComplexProcessing($row); yield $record; } } 

Поэтому, если вам нужны только первые 3 результата, вы обрабатываете только первые три записи.

Для получения дополнительной информации я написал сообщение в блоге по этой теме.

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

Кроме того, что они являются итерируемыми, они не близки друг другу. array – это структура данных, генератор – нет.

Массив должен содержать каждое значение, которое вы зацикливаете до начала цикла; генератор создает каждое значение «на лету» по мере его запроса, поэтому намного меньше памяти;

Массив работает со значениями, которые он содержит, и должен быть предварительно заполнен этими значениями; генератор может создавать значения в соответствии со специальными критериями, которые будут использоваться напрямую … например, последовательность fibonnaci или буквы из алфавита без AZ (рассчитанные по числовому значению UTF-8), эффективно позволяя alphaRange ('א', 'ת' );

РЕДАКТИРОВАТЬ

 function fibonacci($count) { $prev = 0; $current = 1; for ($i = 0; $i < $count; ++$i) { yield $prev; $next = $prev + $current; $prev = $current; $current = $next; } } foreach (fibonacci(48) as $i => $value) { echo $i , ' -> ' , $value, PHP_EOL; } 

РЕДАКТИРОВАТЬ

Просто для удовольствия, вот генератор, который вернет еврейский алфавит как символы UTF-8

 function hebrewAlphabet() { $utf8firstCharacter = 1488; $utf8lastCharacter = 1514; for ($character = $utf8firstCharacter; $character <= $utf8lastCharacter; ++$character) { yield html_entity_decode('&#'.$character.';', ENT_NOQUOTES, 'UTF-8'); }; } foreach(hebrewAlphabet() as $character) { echo $character, ' '; } 

Как и в Python:

Когда итерация по набору элементов начинается с использования оператора for, генератор запускается. Как только код функции генератора достигнет оператора «yield», генератор возвращает его выполнение в цикл for, возвращая новое значение из набора. Функция генератора может генерировать столько значений (возможно, бесконечных), сколько захочет, что дает каждому в свою очередь.

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

learnpython.org