一、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 */