If you want to use generator::send() within a foreach loop, you will most likely get an unexpected result. The Generator::send() method resumes the generator, which means the pointer within the generator is moved to the next element in the generator list.
Here is an example:
<?php
class ApiDummy
{
private static $apiDummyData = ['a', 'b', 'c', 'd', 'e'];
public static function getAll(): Generator {
foreach (self::$apiDummyData as $entry) {
echo 'yielding $elem' . PHP_EOL;
$newElem = (yield $entry);
echo 'yield return: ' . $newElem . PHP_EOL;
}
}
}
$generator = ApiDummy::getAll();
foreach ($generator as $elem) {
echo 'value from generator: ' . $elem . PHP_EOL;
$generator->send($elem . '+');
}
while ($generator->valid()) {
$elem = $generator->current();
echo 'value from generator: ' . $elem . PHP_EOL;
$generator->send($elem . '+');
}
?>
The result of example iteration one:
yielding $elem
value from generator: a
yield return: a+
yielding $elem
yield return:
yielding $elem
value from generator: c
yield return: c+
yielding $elem
yield return:
yielding $elem
value from generator: e
yield return: e+
As you can see, the values b and d are not printed out and also not extended by the + sign.
The foreach loop receives the first yield and the send call causes a second yield within the first loop. Therefor the second loop already receives the third yield and so on.
To avoid this, one solution could be to use a while loop and the Generator::send() method to move the generator cursor forward and the Generator::current() method to retrieve the current value. The loop can be controlled with the Generator::valid() method which returns false, if the generator has finished. See example iterator two.
The expected result of example iteration two:
yielding $elem
value from generator: a
yield return: a+
yielding $elem
value from generator: b
yield return: b+
yielding $elem
value from generator: c
yield return: c+
yielding $elem
value from generator: d
yield return: d+
yielding $elem
value from generator: e
yield return: e+