一、Generator
Generator , 一种能够返回迭代器的生成器,当程序运行到yield的时候,当前程序就唤起协程记录上下文,而后主函数继续操做,当须要操做的时候,在经过迭代器的next从新调起mysql
function xrange($start, $end, $step = 1) { for ($i = $start; $i <= $end; $i += $step) { yield $i; } } foreach (xrange(1, 1000) as $num) { echo $num, "\n"; } /* * 1 * 2 * ... * 1000 */
若是了解过迭代器的朋友,就能够经过上面这一段代码看出Generators的运行流程sql
Generators::rewind() 重置迭代器 Generators::valid() 检查迭代器是否被关闭 Generators::current() 返回当前产生的值 Generators::next() 生成器继续执行 Generators::valid() Generators::current() Generators::next() ... Generators::valid() 直到返回 false 迭代结束
二、Generator应用
不少不了解的朋友看完可能会表示这有什么用呢?数据库
举个栗子:
好比从数据库取出数亿条数据,这个时候要求用一次请求加响应返回全部值该怎么办呢?获取全部值,而后输出,这样确定不行,由于会形成PHP内存溢出的,由于数据量太大了。若是这时候用yield就能够将数据分段获取,理论上这样是能够取出无限的数据的。函数
通常的获取方式 :fetch
数据库链接..... $sql = "select * from `user` limit 0,500000000"; $stat = $pdo->query($sql); $data = $stat->fetchAll(); //mysql buffered query遍历巨大的查询结果致使的内存溢出 var_dump($data);
yield获取方式:spa
数据库链接..... function get(){ $sql = "select * from `user` limit 0,500000000"; $stat = $pdo->query($sql); while ($row = $stat->fetch()) { yield $row; } } foreach (get() as $row) { var_dump($row); }
三、Generator::sendcode
向生成器中传入一个值,而且当作 yield 表达式的结果,而后继续执行生成器。
若是当这个方法被调用时,生成器不在 yield 表达式,那么在传入值以前,它会先运行到第一个 yield 表达式。As such it is not necessary to “prime” PHP generators with a Generator::next() call (like it is done in Python)
这表明了什么,这表明了咱们可使用yield进行双向通讯协程
再举个栗子blog
$ben = call_user_func(function (){ $hello = (yield 'my name is ben ,what\'s your name'.PHP_EOL); echo $hello; }); $sayHello = $ben->current(); echo $sayHello; $ben->send('hi ben ,my name is alex'); /* * output * * my name is ben ,what's your name * hi ben ,my name is alex */
这样ben跟alex他们两个就实现了一次相互问好,在这个例子中咱们能够发现,yield跟以往的return不一样,它不只能够返回数据,还能够获取外部返回的数据内存
并且不单单可以send,PHP还提供了一个throw,容许咱们返回一个异常给Generator
$Generatorg = call_user_func(function(){ $hello = (yield '[yield] say hello'.PHP_EOL); echo $hello.PHP_EOL; try{ $jump = (yield '[yield] I jump,you jump'.PHP_EOL); }catch(Exception $e){ echo '[Exception]'.$e->getMessage().PHP_EOL; } }); $hello = $Generatorg->current(); echo $hello; $jump = $Generatorg->send('[main] say hello'); echo $jump; $Generatorg->throw(new Exception('[main] No,I can\'t jump')); /* * output * * [yield] say hello * [main] say hello * [yield] I jump,you jump * [Exception][main] No,I can't jump */