首页 > 编程 > PHP > 正文

PHP7中生成器的新特性:生成器委托( yield-from )&返回值(return-value)

2020-03-22 17:24:49
字体:
来源:转载
供稿:网友
这篇文章给大家介绍的内容是关于PHP7中生成器的新特性:生成器委托( yield-from ) 返回值(return-html' target='_blank'>value),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

生成器委托

简单地翻译官方文档的描述:

PHP7中,通过生成器委托(yield from),可以将其他生成器、可迭代的对象、数组委托给外层生成器。外层的生成器会先顺序 yield 委托出来的值,然后继续 yield 本身中定义的值。

利用 yield from 可以方便我们编写比较清晰生成器嵌套,而代码嵌套调用是编写复杂系统所必需的。
上例子:

 ?phpfunction echoTimes($msg, $max) { for ($i = 1; $i = $max; ++$i) { echo $msg iteration $i/n  yield;function task() { yield from echoTimes( foo , 10); // print foo ten times echo ---/n  yield from echoTimes( bar , 5); // print bar five timesforeach (task() as $item) {}

以上将输出:

foo iteration 1foo iteration 2foo iteration 3foo iteration 4foo iteration 5foo iteration 6foo iteration 7foo iteration 8foo iteration 9foo iteration 10bar iteration 1bar iteration 2bar iteration 3bar iteration 4bar iteration 5

自然,内部生成器也可以接受它的父生成器发送的信息或者异常,因为 yield from 为父子生成器建立一个双向的通道。不多说,上例子:

 ?phpfunction 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 $i/n 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() 表达式。

上例子:

 ?phpfunction echoTimes($msg, $max) { for ($i = 1; $i = $max; ++$i) { echo $msg iteration $i/n  yield; return $msg the end value : $i/n 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服务器

现在我们利用 PHP7 中的这两个新特性重写这个 web 服务器,只需要 100 多行代码。

代码如下:

 ?phpclass 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 = RESHTTP/1.1 200 OKContent-Type: text/plainContent-Length: 12Connection: closehello world! return $response;});

相关文章推荐:

PHP生成器Generators的简单解析

以上就是PHP7中生成器的新特性:生成器委托( yield-from ) 返回值(return-value)的详细内容,PHP教程

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表