Search code examples
phpresetyieldyield-from

How to reset yield from within a generator in PHP


I am trying to setting up a coupled yield function. But when the function is called the second time, the integrated yield from is not reset.

I think the simplest way is to show using an example:

Code Example

PHP

class GeneratorTest
{

    public function generatorA() {
        for ($i = 0; $i < 10; $i++) {
            yield $i;
        }
    }


    // Generators can yield from other generators
    public function generatorB() {
        yield from $this->generatorA();  // << why is this not reset?

        for($i = 0; $i < 26; $i++) {
            yield chr(65 + $i);
        }
    }

}


$gen = new GeneratorTest();

echo "Test 1 from Generator B<br>";
foreach ($gen->generatorB() as $item) {
    echo $item . "<br>";
}

echo "Test 2 from Generator B<br>";
print_r(iterator_to_array($gen->generatorB()));

Expected?

I expected the output of "Test 2" to be identical to "Test 1". But actually it seems that the yield from generator is not reset when used.

Edit / Important:

Like noted by @Ganesh Wagh: Calling the generator in a second "for-each" works perfectly. The problem really only occurs, when calling "iterator_to_array"! Is this the expected behavior.

I tried to reset generatorA at the end of generatorB like this:

PHP

public function generatorB() {
    yield from $this->generatorA();

    for($i = 0; $i < 26; $i++) {
        yield chr(65 + $i);
    }
    $this->generatorA()->reset();
}

But to no avail.

Question: Is this the expected behavior? What do I have to do to reset the "inner" generator?


Solution

  • All credit goes to @Frankich! (Second comment)

    The problem was, that "iterator_to_array" evaluated the keys of the generator.

    So a generator silently returns the keys of the used generator (yield from):

    echo "Test 1 from Generator B\n";
    foreach ($gen->generatorB() as $key => $item) {
        echo $key . '=>' .  $item . "\n";
    }
    
    

    Results in:

    1=>1
    2=>2
    ...
    0=>A
    1=>B
    2=>C
    ...
    

    So the keys in: iterator_to_array($gen->generatorB())) where overwritten (like pointed out by @Frankich)!

    and only: iterator_to_array($gen->generatorB()), false) prevented that.

    Thx for the input!