note 126068 added to generator.send
| From: | php at didatus dot de | Date: | Mon, 10 May 2021 20:09:38 +0000 |
| Subject: | note 126068 added to generator.send | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-216369@lists.php.net to get a copy of this message | ||
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();
// example iteration one with unexpected result
foreach ($generator as $elem) {
echo 'value from generator: ' . $elem . PHP_EOL;
$generator->send($elem . '+');
}
// example iteration two with the expected result
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+
----
Server IP: 45.112.84.4
Probable Submitter: 45.112.85.242 (proxied: 2a04:4540:6812:8b00:6183:431e:7bd5:92f7)
----
Manual Page -- https://php.net/manual/en/generator.send.php
Edit -- https://main.php.net/note/edit/126068
Del: integrated -- https://main.php.net/note/delete/126068/integrated
Del: useless -- https://main.php.net/note/delete/126068/useless
Del: bad code -- https://main.php.net/note/delete/126068/bad+code
Del: spam -- https://main.php.net/note/delete/126068/spam
Del: non-english -- https://main.php.net/note/delete/126068/non-english
Del: in docs -- https://main.php.net/note/delete/126068/in+docs
Del: other reasons-- https://main.php.net/note/delete/126068
Reject -- https://main.php.net/note/reject/126068
Search -- https://main.php.net/manage/user-notes.php