(PHP 5 >= 5.5.0, PHP 7, PHP 8)
Os generators fornecem uma maneira fácil de implementar simples iterators sem a sobrecarga ou complexidade de criar uma classe que implemente a interface Iterator.
Um generator permite que você escreva código que use foreach para iterar em um conjunto de dados sem precisar construir um array em memória, o que pode fazer com que o limite de memória seja ultrapassado ou exigir uma quantidade considerável de tempo de processamento para a geração. Em vez disso, você pode escrever uma função generator, que é o mesmo que uma função normal, exceto que ao invés do retorno ocorrer única vez, um generator pode entregar o resultado quantas vezes forem necessárias para permitir que os valores sejam iterados.
Um exemplo simples para isso é reimplementar a função range(). A função range() padrão tem que gerar um array com cada valor dentro dele e retorná-lo, o que pode resultar em grandes arrays: por exemplo, chamando range(0, 1000000) irá resultar numa utilização de memória de mais de 100 MB.
Como alternativa, nós podemos implementar um generator
xrange()
, que só precisará de memória suficiente para
criar um objeto Iterator e acompanhar o estado atual
do generator internamente, que utiliza menos de 1 kilobyte de memória.
Exemplo #1 Implementando range() como um generator
<?php
function xrange($start, $limit, $step = 1) {
if ($start < $limit) {
if ($step <= 0) {
throw new LogicException('Step must be +ve');
}
for ($i = $start; $i <= $limit; $i += $step) {
yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('Step must be -ve');
}
for ($i = $start; $i >= $limit; $i += $step) {
yield $i;
}
}
}
/*
* Note that both range() and xrange() result in the same
* output below.
*/
echo 'Single digit odd numbers from range(): ';
foreach (range(1, 9, 2) as $number) {
echo "$number ";
}
echo "\n";
echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
echo "$number ";
}
?>
O exemplo acima irá imprimir:
Single digit odd numbers from range(): 1 3 5 7 9 Single digit odd numbers from xrange(): 1 3 5 7 9
Quando uma função geradora é chamada uma primeira vez, um objeto interno de tipo Generator é retornado. Este objeto implementa a interface Iterator que um objeto somente leitura de uma direção implementaria, provendo também métodos que podem ser utilizados para manipular o estado do gerador, incluindo enviar e retornar valores.