帶你瞭解PHP7裡生成器的新特性
中,透過生成器委託(yield from),可以將其他生成器、可迭代的物件、陣列委託給外層生成器。外層的生成器會先順序 yield 委託出來的值,然後繼續 yield 本身中定義的值。
利用 yield from 可以方便我們編寫比較清晰生成器巢狀,而程式碼巢狀呼叫是編寫複雜系統所必需的。
上例子:
<?php function echoTimes($msg, $max) { for ($i = 1; $i <= $max; ++$i) { echo "$msg iteration $in"; yield; } } function task() { yield from echoTimes('foo', 10); // print foo ten times echo "---n"; yield from echoTimes('bar', 5); // print bar five times } foreach (task() as $item) { ; }
以上將輸出:
foo iteration 1 foo iteration 2 foo iteration 3 foo iteration 4 foo iteration 5 foo iteration 6 foo iteration 7 foo iteration 8 foo iteration 9 foo iteration 10 --- bar iteration 1 bar iteration 2 bar iteration 3 bar iteration 4 bar iteration 5
自然,內部生成器也可以接受它的父生成器傳送的資訊或者異常,因為 yield from 為父子生成器建立一個雙向的通道。不多說,上例子:
<?php function echoMsg($msg) { while (true) { $i = yield; if($i === null){ break; } if(!is_numeric($i)){ throw new Exception("Hoo! must give me a number"); } echo "$msg iteration $in"; } } function task2() { yield from echoMsg('foo'); echo "---n"; yield from echoMsg('bar'); } $gen = task2(); foreach (range(1,10) as $num) { $gen->send($num); } $gen->send(null); foreach (range(1,5) as $num) { $gen->send($num); } //$gen->send("hello world"); //try it ,gay
輸出和上個例子是一樣的。
生成器返回值
如果生成器被迭代完成,或者執行到 return 關鍵字,是會給這個生成器返回值的。
可以有兩種方法獲取這個返回值:
- 使用 $ret = Generator::getReturn() 方法。
- 使用 $ret = yield from Generator() 表示式。
上例子:
<?php function echoTimes($msg, $max) { for ($i = 1; $i <= $max; ++$i) { echo "$msg iteration $in"; yield; } return "$msg the end value : $in"; } function task() { $end = yield from echoTimes('foo', 10); echo $end; $gen = echoTimes('bar', 5); yield from $gen; echo $gen->getReturn(); } foreach (task() as $item) { ; }
輸出結果就不貼了,想必大家都猜到。
可以看到 yield from 和 return 結合使得 yield 的寫法更像平時我們寫的同步模式的程式碼了,畢竟,這就是 PHP 出生成器特性的原因之一呀。
一個非阻塞的web伺服器
時間回到2015年,鳥哥部落格上轉載的一篇《 在PHP中使用協程實現多工排程》。文章介紹了PHP5 的迭代生成器,協程,並實現了一個簡單的非阻塞 web 伺服器。(連結見文末引用)
現在我們利用 PHP7 中的這兩個新特性重寫這個 web 伺服器,只需要 100 多行程式碼。
程式碼如下:
<?php class CoSocket { protected $masterCoSocket = null; public $socket; protected $handleCallback; public $streamPoolRead = []; public $streamPoolWrite = []; public function __construct($socket, CoSocket $master = null) { $this->socket = $socket; $this->masterCoSocket = $master ?? $this; } public function accept() { $isSelect = yield from $this->onRead(); $acceptS = null; if ($isSelect && $as = stream_socket_accept($this->socket, 0)) { $acceptS = new CoSocket($as, $this); } return $acceptS; } public function read($size) { yield from $this->onRead(); yield ($data = fread($this->socket, $size)); return $data; } public function write($string) { yield from $this->onWriter(); yield fwrite($this->socket, $string); } public function close() { unset($this->masterCoSocket->streamPoolRead[(int)$this->socket]); unset($this->masterCoSocket->streamPoolWrite[(int)$this->socket]); yield ($success = @fclose($this->socket)); return $success; } public function onRead($timeout = null) { $this->masterCoSocket->streamPoolRead[(int)$this->socket] = $this->socket; $pool = $this->masterCoSocket->streamPoolRead; $rSocks = []; $wSocks = $eSocks = null; foreach ($pool as $item) { $rSocks[] = $item; } yield ($num = stream_select($rSocks, $wSocks, $eSocks, $timeout)); return $num; } public function onWriter($timeout = null) { $this->masterCoSocket->streamPoolWrite[(int)$this->socket] = $this->socket; $pool = $this->masterCoSocket->streamPoolRead; $wSocks = []; $rSocks = $eSocks = null; foreach ($pool as $item) { $wSocks[] = $item; } yield ($num = stream_select($rSocks, $wSocks, $eSocks, $timeout)); return $num; } public function onRequest() { /** @var self $socket */ $socket = yield from $this->accept(); if (empty($socket)) { return false; } $data = yield from $socket->read(8192); $response = call_user_func($this->handleCallback, $data); yield from $socket->write($response); return yield from $socket->close(); } public static function start($port, callable $callback) { echo "Starting server at port $port...n"; $socket = @stream_socket_server("tcp://0.0.0.0:$port", $errNo, $errStr); if (!$socket) throw new Exception($errStr, $errNo); stream_set_blocking($socket, 0); $coSocket = new self($socket); $coSocket->handleCallback = $callback; function gen($coSocket) { /** @var self $coSocket */ while (true) yield from $coSocket->onRequest(); } foreach (gen($coSocket) as $item){}; } } CoSocket::start(8000, function ($data) { $response = <<<RES HTTP/1.1 200 OK Content-Type: text/plain Content-Length: 12 Connection: close hello world! RES; return $response; });
以上就是帶你瞭解PHP7裡生成器的新特性的詳細內容,更多請關注php中文網其它相關文章!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2370/viewspace-2827215/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 使用示例帶你提前瞭解 Java 9 中的新特性Java
- JDK8新特性-你瞭解多少JDK
- JDK9新特性-你瞭解多少JDK
- JDK10新特性-你瞭解多少JDK
- php7的新特性PHP
- PHP7 新特性PHP
- php7新特性PHP
- 帶你瞭解資料庫中事務的ACID特性資料庫
- 帶你瞭解webpackWeb
- Java8新特性,你應該瞭解這些!Java
- 帶你快速瞭解HTMLHTML
- 三分鐘,帶你瞭解EOS新資源模型模型
- 十分鐘,帶你瞭解 Vue3 的新寫法Vue
- 帶你全面瞭解 Flutter,它好在哪裡?它的坑在哪裡? 應該怎麼學?Flutter
- 大咖帶你解讀 PostgreSQL 15 新特性 | 直播預告SQL
- 萬字帶你瞭解ChatGLM
- 你不得不瞭解 Helm 3 中的 5 個關鍵新特性
- 帶你瞭解IP地址的計算
- 帶你真正的瞭解加密和Hash加密
- 你真的瞭解python嗎?這篇文章帶你快速瞭解!Python
- NVIDIA RTX30系列顯示卡有哪些新特性?一文帶你瞭解RTX30系顯示卡
- 帶你瞭解代理 IP 那些事
- 帶你了從零瞭解DockerDocker
- 帶你瞭解 Angular 與 Angular JSAngularJS
- 帶你全面瞭解 OAuth2.0OAuth
- 帶你瞭解小程式生態
- 8張圖帶你瞭解iptables的前世今生
- 乾貨|一文帶你瞭解 Apache Hive2.x 的四大特性ApacheHive
- Solon 3.0 新特性:HttpUtils 瞭解一下HTTP
- 帶你瞭解TCP/IP協議族TCP協議
- 帶你瞭解redux與react-reduxReduxReact
- 帶你瞭解資料庫中JOIN的用法資料庫
- 帶你瞭解資料庫中group by的用法資料庫
- 帶你瞭解大語音模型的前世今生模型
- 一文帶你瞭解 JS Module 的始末JS
- 帶你瞭解GaussDB SQL中的BOOLEAN表示式SQLBoolean
- 帶你一起敲敲ES6的新特性,邊解釋邊應用!
- 瞭解SQL Server 2008的新壓縮特性SQLServer