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

标签 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

我正在尝试用 PHP 模拟一些类似的东西,但这有点让人头疼。

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

在我继续之前,我在 PHP 中遇到了这个错误

Fatal error: Generators cannot return values using "return"

好吧,也许我会使用另一个 yield 来获取最终值? ...

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

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

好的,所以我找回了我的值(value),但这里有两个主要问题

  1. 我的 "a" 去了哪里? — 注意在 JS 示例中我能够访问 "a"“b” 产生值以及 100 最终结果。

  2. 生成器还没有完成! — 我必须再调用一次 send 来完成生成器

    $g->valid();   //=> true
    $g->send('?'); //=> null
    $g->valid();   //=> false
    

来自 PHP Generator::send

public mixed Generator::send ( mixed $value )

Sends the given value to the generator as the result of the current yield expression and resumes execution of the generator.

If the generator is not at a yield expression when this method is called, it will first be let to advance to the first yield expression before sending the value. As such it is not necessary to "prime" PHP generators with a Generator::next() call (like it is done in Python).

强调“因此没有必要使用 Generator::next() 来“启动”PHP 生成器”。好的,但这到底是什么意思?我不必像 JavaScript 示例那样“启动”它,但第一个产生的值也会被吞没。

谁能解释一下您是如何在使用foreach 的情况下单步执行生成器的?

最佳答案

第一个产生的值并没有被吞噬,你只是从未看过它。

$g = powGenerator();
echo $g->current(); //a

然后你两次发送值并恢复执行,$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

这将输出:

a
b
100
Okay, finishing here now!
bool(false)

现在在 PHP 7 中,您可以 return from a generator .

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";

哪些输出:

a
b

bool(false)
100

至于在没有 foreach 的情况下单步执行它们 - Generator工具 Iterator ,所以它有适当的方法来处理它:current , key , next , rewind , 和 valid .需要注意的是,如果您在已经开始的生成器上调用它,rewind 将抛出异常。

执行此操作并演示 PHP 7 的新 generator delegation 的示例:

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

$g = letterGenerator();

while ($g->valid()) {
    echo $g->current();
    $g->next();
}

输出:

abcdefghijklmnopqrstuvwxyz

关于php - 如何在没有 foreach 的情况下使用 PHP 生成器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32960408/

相关文章:

javascript - js 生成器函数中的第一个 next() 是否总是执行到第一个 yield?

python - Python 协程可以不用 await 或 yield 实现吗?

php - 使用 PHP 和 HTML 显示 MYSQL 数据

PHP If/else 用户存在于数据库中将变量设置为 0 或 1

php - Laravel 循环收集成小块

javascript - 如何在 typescript 中注释生成器函数

javascript - 从 YAML 生成 javascript 类/对象

javascript - 使用JS执行MySQL查询及其涉及的安全问题

php - 在 If 语句插入数据库

PHP生成器函数解释