Generators
PHP Manual

Sintaxe do Generator

Uma função generator se parece com uma função normal, exceto que ao invés de retornar um valor, um generator pode entregar o resultado quantas vezes forem necessárias.

Quando uma função generator é chamada, ela retorna um objeto que pode ser iterado. Quando você itera através desse objeto (por exemplo, por um loop foreach), o PHP irá chamar a função generator toda vez que precisar de um valor, em seguida salva o estado do generator quando o valor é produzido, de modo que possa ser retomado quando o próximo valor for necessário.

Uma vez que não há mais valores a serem produzidos, a função generator pode simplesmente sair, e a chamada de código continua como se um array tivesse executado os valores.

Nota:

Um generator não pode retornar um valor: isso resultará num erro de compilação. Um retorno vazio é uma sintaxe válida e fará com que o generator seja encerrado.

A palavra chave yield

O coração de uma função generator é a palavra chave yield. Na sua forma mais simples, uma declaração yield se parece muito com um retorno, exceto que em vez de parar a execução da função e retornar, o yield fornece um valor para o código de loop sobre o generator e pausa a execução da função do generator.

Exemplo #1 Um exemplo simples de valores yield

<?php
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";
}
?>

O exemplo acima irá imprimir:

1
2
3

Nota:

Internamente, chaves inteiras sequenciais serão pareadas com os valores entregues, assim como um array não associativo.

Cuidado

Se você usar um yield em um contexto da expressão (por exemplo, a direita de uma atribuição), você deve colocar a declaração yield entre parênteses no PHP 5. Por exemplo, isso é válido:

$data = (yield $value);

Mas isso não é válido terá como resultado um parse error no PHP 5:

$data = yield $value;

Os parênteses não são necessário no PHP 7.

A sintaxe pode ser usada em conjunto com o método Generator::send().

Produzindo valores com chaves

O PHP suporta arrays associativos e generators não são diferentes. Além do produzir valores simples, como mostrado acima, você também pode produzir uma chave ao mesmo tempo.

A sintaxe para preparar um par de chave/valor é muito semelhante ao utilizado para definir um array associativo, como mostrado abaixo.

Exemplo #2 Produzindo um par de chave/valor

<?php
/*
 * The input is semi-colon separated fields, with the first
 * field being an ID to use as a key.
 */

$input = <<<'EOF'
1;PHP;Likes dollar signs
2;Python;Likes whitespace
3;Ruby;Likes blocks
EOF;

function 
input_parser($input) {
    foreach (
explode("\n"$input) as $line) {
        
$fields explode(';'$line);
        
$id array_shift($fields);

        
yield $id => $fields;
    }
}

foreach (
input_parser($input) as $id => $fields) {
    echo 
"$id:\n";
    echo 
"    $fields[0]\n";
    echo 
"    $fields[1]\n";
}
?>

O exemplo acima irá imprimir:

1:
    PHP
    Likes dollar signs
2:
    Python
    Likes whitespace
3:
    Ruby
    Likes blocks
Cuidado

Da mesma forma como acontece com o yield de valores simples mostrados anteriormente, produzir um par de chave/valor num contexto da expressão requer que a declaração do yield esteja entre parênteses:

$data = (yield $key => $value);

Produzindo valores nulos

O yield pode ser chamado sem um argumento para produzir um valor NULL com uma chave automática.

Exemplo #3 Produzindo valores NULLos

<?php
function gen_three_nulls() {
    foreach (
range(13) as $i) {
        
yield;
    }
}

var_dump(iterator_to_array(gen_three_nulls()));
?>

O exemplo acima irá imprimir:

array(3) {
  [0]=>
  NULL
  [1]=>
  NULL
  [2]=>
  NULL
}

Produzindo valores por referência

Funções generator são capazes de produzir valores por referência bem como por valor. Isso é feito da mesma forma que retornar referências de funções: incluindo um & no início do nome da função.

Exemplo #4 Produzindo valores por referência

<?php
function &gen_reference() {
    
$value 3;

    while (
$value 0) {
        
yield $value;
    }
}

/*
 * Note that we can change $number within the loop, and
 * because the generator is yielding references, $value
 * within gen_reference() changes.
 */
foreach (gen_reference() as &$number) {
    echo (--
$number).'... ';
}
?>

O exemplo acima irá imprimir:

2... 1... 0...

Delegação de gerador viayield from

No PHP 7 a delegação de gerador permite retornar valores de outro gerador, objeto Traversable ou um array utilizando para isso a instrução yield from. O gerador externo retornará todos os valores do gerador interno, objeto ou array até que o mesmo não seja mais válido, a partir de onde a execução continuará no gerador externo.

Se um gerador é utilizado com yield from, a expressão yield from também retornará qualquer valor retornado pelo gerador interno.

Exemplo #5 Uso básico de yield from

<?php
function count_to_ten() {
    
yield 1;
    
yield 2;
    
yield from [34];
    
yield from new ArrayIterator([56]);
    
yield from seven_eight();
    
yield 9;
    
yield 10;
}

function 
seven_eight() {
    
yield 7;
    
yield from eight();
}

function 
eight() {
    
yield 8;
}

foreach (
count_to_ten() as $num) {
    echo 
"$num ";
}
?>

O exemplo acima irá imprimir:

1 2 3 4 5 6 7 8 9 10

Exemplo #6 yield from e valores retornados

<?php
function count_to_ten() {
    
yield 1;
    
yield 2;
    
yield from [34];
    
yield from new ArrayIterator([56]);
    
yield from seven_eight();
    return 
yield from nine_ten();
}

function 
seven_eight() {
    
yield 7;
    
yield from eight();
}

function 
eight() {
    
yield 8;
}

function 
nine_ten() {
    
yield 9;
    return 
10;
}

$gen count_to_ten();
foreach (
$gen as $num) {
    echo 
"$num ";
}
echo 
$gen->getReturn();
?>

O exemplo acima irá imprimir:

1 2 3 4 5 6 7 8 9 10

Generators
PHP Manual