说到php中的Generator(生成器),有人可能会想到协程,这里咱们先不说php如何实现协程,咱们探究下Generator的执行过程。
Generator是经过yield实现,yield 关键字是php5.5版本推出的一个特性。
首先,看下面的代码:php
function gen(){ while(true){ yield "gen\n"; } } $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 接口的方式,性能开销和复杂性大大下降。
列子:spa
function gen(){ for($i=0;$i<5;$i++) { echo (yield $i).$i.'<br/>'; } } $gen = gen(); foreach($gen as $k=>$v){ echo "{$k}---{$v}".'<br/>'; }
结果是:.net
从上面的结果,咱们能够分析出如下几点:
1当Generator对象被foreach的时候,内部的valid,current,key方法会依次被调用,其返回值是foreach语句的value和key。
2循环的终止条件则根据valid方法的返回而定。若是返回的是true则继续循环,若是是false则终止整个循环,结束遍历。
3一次循环体结束以后,将调用next进行下一次的循环直到valid返回false。而rewind方法则是在整个循环开始前被调用(也就是生成Generator对象时),这样保证了咱们屡次遍历获得的结果都是一致的。翻译
下面咱们来证实一下这个流程:code
$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.'<br/>';因为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.'<br/>',当前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...。