资讯专栏INFORMATION COLUMN

php中Generator的执行过程

Caicloud / 2431人阅读

摘要:说到中的生成器,有人可能会想到协程,这里我们先不说如何实现协程,我们探究下的执行过程。如果函数包含了关键字的,那么函数执行后的返回值永远都是一个对象。如果函数内部同事包含和该函数的返回值依然是对象,但是在生成对象时,语句后的代码被忽略。

说到php中的Generator(生成器),有人可能会想到协程,这里我们先不说php如何实现协程,我们探究下Generator的执行过程。
Generator是通过yield实现,yield 关键字是php5.5版本推出的一个特性。
首先,看下面的代码:

                function gen(){
                  while(true){
                    yield "gen
";
                  }
                }
                
                $gen = gen();
                echo "Generator"; 
                

如果没有了解过yield的话,你会认为上面代码执行的结果是:死循环。但实际上,它会echo出Generator。

到这里,也许你会觉得奇怪,yield怎么可以结束循环?下面就为大家说明一下:

Generator提供的方法:

Generator::current — 返回当前产生的值
Generator::key — 返回当前产生的键
Generator::next — 生成器继续执行
Generator::rewind — 重置迭代器
Generator::send — 向生成器中传入一个值
Generator::throw — 向生成器中抛入一个异常
Generator::valid — 检查迭代器是否被关闭
Generator::__wakeup — 序列化回调

生成器提供了一种更容易的方法来实现简单的对象迭代(迭代器),相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。

列子:

              function gen(){
                   for($i=0;$i<5;$i++)
                   {
                       echo (yield $i).$i."
"; } } $gen = gen(); foreach($gen as $k=>$v){ echo "{$k}---{$v}"."
"; }

结果是:

从上面的结果,我们可以分析出以下几点:
1当Generator对象被foreach的时候,内部的valid,current,key方法会依次被调用,其返回值是foreach语句的value和key。
2循环的终止条件则根据valid方法的返回而定。如果返回的是true则继续循环,如果是false则终止整个循环,结束遍历。
3一次循环体结束之后,将调用next进行下一次的循环直到valid返回false。而rewind方法则是在整个循环开始前被调用(也就是生成Generator对象时),这样保证了我们多次遍历得到的结果都是一致的。

下面我们来证明一下这个流程:

$gen = gen();
echo $gen->key();//结果是0,生成Generator对象时,rewind已经执行。
echo $gen->key()."----".$gen->current();// 0----0
var_dump($gen->next());//var_dump值是null,但是还会echo出多一个0;这个0是怎样来的呢?原因是:next()执行后,第1个yield到第二个yieldz之间的的语法被执行,即是:echo (yield $i).$i."
";由于next()是没有返回值,即(yield $i)这个表达式没有值,而$i的值是0;
echo $gen->key()."----".$gen->current();// 1----1 目前是第2个yield

上面这个例子可以证明,Generator内部的流程,特别注意next()的理解。

最后,我们说一下,send():

官方解析:向生成器中传入一个值,并且当做 yield 表达式的结果,然后继续执行生成器。如果当这个方法被调用时,生成器不在 yield 表达式,那么在传入值之前,它会先运行到第一个 yield 表达式。

翻译下的结论是:
send()方法主要用于发送数据给当前yield,即yield表达式被当作一个值被替换,且继续执行下一个yield,即next()

证明例子:
$gen = gen();
$gen->send(666);//6660

6660结果分析:首先把666代替当前yield表达式的值,然后执行next(),即运行echo (yield $i).$i."
",当前yield是666,所以最终结果是:6660。注意与next()的区别!!!

总结:
1.yield只能用于函数内部,在非函数内部运用会抛出错误。
2.如果函数包含了yield关键字的,那么函数执行后的返回值永远都是一个Generator对象。
3.如果函数内部同事包含yield和return 该函数的返回值依然是Generator对象,但是在生成Generator对象时,return语句后的代码被忽略。
4.Generator类实现了Iterator接口。
5.可以通过返回的Generator对象内部的方法,获取到函数内部yield后面表达式的值。
6.可以通过Generator的send方法给yield 关键字赋一个值。
7.一旦返回的Generator对象被遍历完成,便不能调用他的rewind方法来重置。
8.Generator对象不能被clone关键字克隆 。

实际应用:
1.协程
2.Genenrator返回的是迭代器,在处理大数据的时候不用一次性的加载到内存中,可看http://php.net/manual/zh/lang...。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/28265.html

相关文章

  • PHP生成器

    摘要:它最简单的调用形式看起来像一个申明,不同之处在于普通会返回值并终止函数的执行,而会返回一个值给循环调用此生成器的代码并且只是暂停执行生成器函数。 0x01 写在前面 本文主要介绍: Generator的简单用法。 Generator的底层实现。 本文比较长,可能会耗费你比较多的时间。如果你比较了解Generator的用法,仅想了解底层实现,可以直接跳到底层实现部分。 本文分析的PH...

    LMou 评论0 收藏0
  • Generator 异常处理

    摘要:的方法在中,提供了方法来抛出异常。总结关于生成器的异常处理,这里来进行一下总结。最近在研究使用实现半协程,而这个过程中,对异常的处理,是非常重要的。但是的运行方式决定了异常处理比较难以理解。 本文是我在研究 PHP 异步编程时的总结。对于相当多的 PHPer 来说,可能都不知道 Generator,或者对 Generaotr 的流程不是很熟悉。因为 Generator 使得程序不再是顺...

    Bmob 评论0 收藏0
  • PHP 生成器入门

    摘要:执行语句的唯一目的是结束生成器执行。这就是需要生成器需要有返回值的意义,这也是为何我们将这个特性加入到中的原因,我们会将最后执行的值作为返回值,但这不是一个好的解决方案。 本文首发于 入门 PHP 生成器,转载请注明出处。 PHP 在 5.5 版本中引入了「生成器(Generator)」特性,不过这个特性并没有引起人们的注意。在官方的 从 PHP 5.4.x 迁移到 PHP 5.5.x...

    IamDLY 评论0 收藏0
  • PHP回顾之协程

    摘要:本文先回顾生成器,然后过渡到协程编程。其作用主要体现在三个方面数据生成生产者,通过返回数据数据消费消费者,消费传来的数据实现协程。解决回调地狱的方式主要有两种和协程。重点应当关注控制权转让的时机,以及协程的运作方式。 转载请注明文章出处: https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie web响应 sess...

    Java3y 评论0 收藏0
  • 浅入理解 PHP Generator

    摘要:在中,我们都知道,有一个函数叫做,用来生成一个等差数列的数组,然后我们可以用这个数组进行的迭代。这一段代码就会输出首项为,末项为,公差为的等差数列。它的执行顺序是这样的。 何为 Generator 从 PHP 5.5 开始,PHP 加入了一个新的特性,那就是 Generator,中文译为生成器。生成器可以简单地用来实现对象的迭代,让我们先从官方的一个小例子说起。 xrange 在 PH...

    wujl596 评论0 收藏0

发表评论

0条评论

Caicloud

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<