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

时间:2015-10-06 01:41:26

标签: 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中遇到了这个错误

  

致命错误:生成器无法使用“return”

返回值

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

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

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

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

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

  2. 生成器仍未完成! - 我必须再次致电send以完成生成器

    $g->valid();   //=> true
    $g->send('?'); //=> null
    $g->valid();   //=> false
    
  3. 来自PHP Generator::send

      

    public mixed Generator::send ( mixed $value )

         

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

         

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

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

    任何人都可以解释一下你是如何使用foreach逐步完成而不是的生成器?

1 个答案:

答案 0 :(得分:11)

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

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

您之后两次发送值并恢复执行,$g->valid()之后trueyield,因为您在第三个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 之后没有恢复 - 生成器isn& #39; t完成,可能还有更多工作要做。考虑:

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

这个&lt; ll输出:

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

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

a
b

bool(false)
100

哪个输出:

foreach

至于在没有rewind - Generator工具Iterator的情况下单步执行它们,所以它有适当的方法来处理它:current,{ {3}},keynextrewind。需要注意的是,如果您在已经开始的生成器上调用它,function letterGenerator() { yield from range('a', 'z'); } $g = letterGenerator(); while ($g->valid()) { echo $g->current(); $g->next(); } 将抛出异常。

这样做的一个例子也演示了PHP 7的新valid

abcdefghijklmnopqrstuvwxyz

输出:

<div class="tree">
    <ul>
        <li>
            <div class="dados_membro">Me</div>
            <ul>
                <li>
                    <div class="dados_membro">Father</div>
                    <ul>
                        <li>
                            <div class="dados_membro">Grandfather</div>
                        </li>
                        <li>
                            <div class="dados_membro">Grandmother</div>
                        </li>
                    </ul>
                </li>
                <li>
                    <div class="dados_membro">Mother</div>
                    <ul>
                        <li>
                            <div class="dados_membro">Grandfather</div>
                        </li>
                        <li>
                            <div class="dados_membro">Grandmother</div>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</div>