Generator :: send如何工作?

mpe*_*pen 6 php generator

通常我不会对语言结构感到困惑,但我无法对这里发生的事情做出正面或反面.

<?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);
}
Run Code Online (Sandbox Code Playgroud)

打印:

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 
Run Code Online (Sandbox Code Playgroud)

所以我的循环的每2迭代被跳过,我得到NULL$ans定期.什么??

我以为$ans会得到结果$gen->send,如果我没有在下一个之前发送任何东西yield,那么 $ans就是null,但我总是在每次迭代时发送一些东西,那么这里发生了什么?

mpe*_*pen 1

我认为“foreach”把事情搞砸了。当 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);
}
Run Code Online (Sandbox Code Playgroud)

打印出我所期望的:

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
Run Code Online (Sandbox Code Playgroud)

如果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);
}
Run Code Online (Sandbox Code Playgroud)

印刷:

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
Run Code Online (Sandbox Code Playgroud)

我认为这里发生的情况是send导致action每次while迭代都要迭代两次。如果我们删除这两个,sends()那么我们就会陷入无限循环。所以...send()正在推进迭代器,而current()没有。我认为这也解释了循环中发生的情况foreach- 和foreachsend()在推进迭代器,这就是为什么其他所有结果都被跳过的原因!