如果您想在 foreach 迴圈中使用 generator::send(),您很可能會得到意想不到的結果。Generator::send() 方法會恢復產生器,這意味著產生器中的指標會移動到產生器列表中的下一個元素。
以下是一個例子
<?php
class ApiDummy
{
private static $apiDummyData = ['a', 'b', 'c', 'd', 'e'];
public static function getAll(): Generator {
foreach (self::$apiDummyData as $entry) {
echo '產生 $elem' . PHP_EOL;
$newElem = (yield $entry);
echo 'yield 返回:' . $newElem . PHP_EOL;
}
}
}
$generator = ApiDummy::getAll();
foreach ($generator as $elem) {
echo '從產生器取得的值:' . $elem . PHP_EOL;
$generator->send($elem . '+');
}
while ($generator->valid()) {
$elem = $generator->current();
echo '從產生器取得的值:' . $elem . PHP_EOL;
$generator->send($elem . '+');
}
?>
範例迭代一的結果
產生 $elem
從產生器取得的值:a
yield 返回:a+
產生 $elem
產生 $elem
產生 $elem
從產生器取得的值:c
yield 返回:c+
產生 $elem
產生 $elem
產生 $elem
從產生器取得的值:e
yield 返回:e+
如您所見,值 b 和 d 沒有被印出,也沒有被加上 + 符號。
foreach 迴圈會收到第一個 yield,而 send 呼叫會在第一個迴圈內造成第二個 yield。因此,第二個迴圈已經收到第三個 yield,依此類推。
為了避免這種情況,一個解決方案是使用 while 迴圈以及 Generator::send() 方法來移動產生器游標,並使用 Generator::current() 方法來取得目前的值。迴圈可以用 Generator::valid() 方法來控制,如果產生器已完成,則會返回 false。請參閱範例迭代二。
範例迭代二的預期結果
產生 $elem
從產生器取得的值:a
yield 返回:a+
產生 $elem
從產生器取得的值:a
yield 返回:a+
產生 $elem
從產生器取得的值:c
yield 返回:c+
產生 $elem
產生器產生的值:d
yield 返回值:d+
產生 $elem
從產生器取得的值:e
yield 返回:e+