如何在没有foreach的情况下使用PHP生成器?

Tha*_*you 10 php generator

这是一个简单的JavaScript生成器(来自:http://blog.carbonfive.com/2013/12/01/hanging-up-on-callbacks-generators-in-ecmascript-6/)

function* powGenerator() {
  var result = Math.pow(yield "a", yield "b");
  return result;
}

var g = powGenerator();
console.log(g.next().value);   // "a", from the first yield
console.log(g.next(10).value); // "b", from the second
console.log(g.next(2).value);  // 100, the result
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用类似于PHP的模型,但这有点令人头疼.

<?php
function powGenerator() {
  return pow((yield 'a'), (yield 'b'));
}
Run Code Online (Sandbox Code Playgroud)

在我走得更远之前,我在PHP中遇到了这个错误

致命错误:生成器无法使用"返回"返回值

好吧,也许我会用另一个产量来获得最终价值?...

<?php
function powGenerator() {
  yield pow((yield 'a'), (yield 'b'));
}

$g = powGenerator(); //=> Generator {#180}
echo $g->send(10);   //=> "b"
echo $g->send(2);    //=> 100
Run Code Online (Sandbox Code Playgroud)

好的,所以我恢复了价值,但这里有两个主要问题

  1. "a"去哪儿了?- 请注意,在JS示例中,我能够访问"a"和生成的"b"值以及100最终结果.

  2. 发电机还没有完成!- 我需要send额外的时间来完成发电机

    $g->valid();   //=> true
    $g->send('?'); //=> null
    $g->valid();   //=> false
    
    Run Code Online (Sandbox Code Playgroud)

来自PHP Generator :: send

public mixed Generator::send ( mixed $value )

作为当前yield表达式的结果将给定值发送到生成器并继续执行生成器.

如果在yield调用此方法时生成器不在表达式中,则yield在发送值之前首先让它前进到第一个表达式.因此,没有必要使用Generator :: next()调用"启动"PHP生成(就像在Python中完成一样).

强调"因此没有必要"使用Generator::next()".好的,但这究竟意味着什么?我没有像JavaScript示例那样"填充"它,但是第一个产生的值也被吞噬了.

任何人都可以解释你是如何在没有使用的情况下逐步完成发电机的foreach

use*_*918 13

第一个产生的价值没有被吞噬,你只是从来没有看过它.

$g = powGenerator();
echo $g->current(); //a
Run Code Online (Sandbox Code Playgroud)

然后,您将两次发送值并恢复执行,之后$g->valid()true因为您没有在第三次之后恢复yield- 生成器未完成且可能还有更多要做的事情.考虑:

function powGenerator() {
    yield pow((yield 'a'), (yield 'b'));
    echo "Okay, finishing here now!\n";
}

$g = powGenerator();
echo $g->current(), "\n"; //a
echo $g->send(10), "\n";  //b
echo $g->send(2), "\n";   //100
$g->next();               // Resumes execution of the generator,
                          // which prints its own message and completes.
var_dump($g->valid());    //false
Run Code Online (Sandbox Code Playgroud)

这个'输出:

a
b
100
Okay, finishing here now!
bool(false)
Run Code Online (Sandbox Code Playgroud)

现在在PHP 7中,您可以 从生成器返回.

function powGenerator() {
    return pow((yield 'a'), (yield 'b'));
    echo "This will never print.";
}

$g = powGenerator();
echo $g->current(), "\n"; //a
echo $g->send(10), "\n";  //b
echo $g->send(2), "\n";   // Prints just the newline, you're moving on
                          // to a return which you must get explicitly.
var_dump($g->valid());    // Generator complete, you're free to get the return.
echo $g->getReturn(), "\n";
Run Code Online (Sandbox Code Playgroud)

哪个输出:

a
b

bool(false)
100
Run Code Online (Sandbox Code Playgroud)

至于步进它们没有foreach- Generator实现Iterator,所以它有适当的方法来处理它:current,key,next,rewindvalid.随着该警告rewind,如果你把它在一个已经开始的发电机会抛出异常.

这样做的一个例子也演示了PHP 7的新生成器委派:

function letterGenerator() {
    yield from range('a', 'z');
}

$g = letterGenerator();

while ($g->valid()) {
    echo $g->current();
    $g->next();
}
Run Code Online (Sandbox Code Playgroud)

输出:

abcdefghijklmnopqrstuvwxyz
Run Code Online (Sandbox Code Playgroud)