通常我对语言结构并不感到困惑,但我无法对这里发生的事情做出正面或反面。
<?php
function action() {
for($i=0; $i<10; ++$i) {
$ans = (yield expensive($i));
echo "action $ans\n";
}
}
function expensive($i) {
return $i*2;
}
$gen = action();
foreach($gen as $x) {
echo "loop $x\n";
$gen->send($x);
}
打印:
loop 0
action 0
action
loop 4
action 4
action
loop 8
action 8
action
loop 12
action 12
action
loop 16
action 16
action
所以我的循环的第二次迭代都被跳过了,我定期为NULL
获得$ans
。什么?
我认为$ans
会收到$gen->send
的结果,如果我在下一个yield
之前没有发送任何内容,那么 {{1}将是null,但我总是在每次迭代时发送一些东西,那么这里发生了什么?
答案 0 :(得分:2)
这是一个文档问题。这就是PHP开发人员wrote on a bug report:
next()
和send()
都推进了生成器。这就是发电机的工作原理。显式或隐式地使用next()
意味着无法通过yield返回值,因此代码将变为null - 就像尝试从不具有&#的函数获取返回值一样39;不要做任何事。
换句话说,您无法在send()
内使用foreach
并期望获得有意义的结果。
实际foreach
来电next()
after each iteration。
/** @return Generator */
function action() {
for ($i = 0; $i < 5; $i += 1) {
$answer = (yield $i * 2);
echo "received: $answer\n";
}
}
$gen = action();
while ($gen->valid()) {
$x = $gen->current();
echo "sending $x\n";
$gen->send($x);
$gen->next();
}
现在我们添加了它,代码再次开始行为不端:
sending 0
received: 0
received:
sending 4
received: 4
received:
sending 8
received: 8
如果我们删除有问题的next()
,则代码可以正常运行。
$gen = action();
while ($gen->valid()) {
$x = $gen->current();
echo "sending $x\n";
$gen->send($x);
//$gen->next();
}
输出:
sending 0
received: 0
sending 2
received: 2
sending 4
received: 4
sending 6
received: 6
sending 8
received: 8
对我来说听起来像个错误。 Even HHVM fails with a fatal error.
答案 1 :(得分:1)
我认为&#39; foreach&#39;弄乱了。当foreach循环开始时,会创建一个迭代器,我想它无法处理我向生成器中注入新内容的事实。
此:
<?php
/**
* @return Generator
*/
function action() {
for($i=0; $i<10; ++$i) {
$ans = (yield expensive($i));
echo "action $ans\n";
}
}
function expensive($i) {
return $i*2;
}
$gen = action();
while($gen->valid()) {
$x = $gen->current();
echo "loop $x\n";
$gen->send($x);
}
打印我期待的:
loop 0
action 0
loop 2
action 2
loop 4
action 4
loop 6
action 6
loop 8
action 8
loop 10
action 10
loop 12
action 12
loop 14
action 14
loop 16
action 16
loop 18
action 18
如果每个循环send
不止一次,事情就会变得奇怪:
<?php
/**
* @return Generator
*/
function action() {
for($i=0; $i<10; ++$i) {
$ans = (yield expensive($i));
echo "action $ans\n";
}
}
function expensive($i) {
echo "expensive $i\n";
return $i;
}
$gen = action();
while($gen->valid()) {
$x = $gen->current();
echo "loop $x\n";
$gen->send($x);
$gen->send($x);
}
打印:
expensive 0
loop 0
action 0
expensive 1
action 0
expensive 2
loop 2
action 2
expensive 3
action 2
expensive 4
loop 4
action 4
expensive 5
action 4
expensive 6
loop 6
action 6
expensive 7
action 6
expensive 8
loop 8
action 8
expensive 9
action 8
我认为这里发生的事情是send
导致action
每次while
迭代迭代两次。如果我们删除了两个sends()
,那么我们会陷入无限循环。所以... send()
正在推进迭代器,而current()
却没有。我认为这也解释了foreach
循环的情况 - foreach
和send()
都推进了迭代器,这就是为什么每个其他结果都被跳过了!