生成器委托
简单地翻译官方文档的描述:
PHP7中,通过生成器委托(yield from),可以将其他生成器、可迭代的对象、数组委托给外层生成器。外层的生成器会先顺序 yield 委托出来的值,然后继续 yield 本身中定义的值。
利用 yield from 可以方便我们编写比较清晰生成器嵌套,而代码嵌套调用是编写复杂系统所必需的。
上例子:
~~~
<?php
function 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 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 $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() 表达式。
上例子:
~~~
<?php
function 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服务器
时间回到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;
~~~
- OAuth
- 简介
- 步骤
- 单点登录
- .user.ini
- 时间转换为今天昨天前天几天前
- 获取ip接口
- 协程
- 概念
- yield-from && return-values
- 协程与阻塞的思考
- 中间件
- mysqli异步与php的协程
- 代码片段
- pdo 执行的sql语句
- 二进制安全
- 捕捉异常中断
- global
- 利用cookie模拟登陆
- 解析非正常json
- 简单的对称加密算法
- RSA 加密
- 过滤掉emoji表情
- 判断远程图片是否存在
- 一分钟限制请求100次
- 文件处理
- 多文件上传
- 显示所有文件
- 文件下载和上面显示所有文件配合
- 文件的删除,统计,存数组等
- 图片处理
- 简介
- 验证码
- 图片等比缩放
- 批量添加水印
- beanstalkd
- 安装
- 使用
- RabbitMQ
- 简介
- debain安装
- centos安装
- 常用方法
- 入门
- 工作队列
- 订阅,发布
- 路由
- 主题
- 远程调用RPC
- 消息中间件的选型
- .htaccess
- isset、empty、if区别以及0、‘’、null
- php各版本
- php7.2 不向后兼容的改动
- php中的各种坑
- php7改变
- php慢日志
- 邮件
- PHPMailer实现发邮件
- 验证邮件地址真实性
- 文件下载
- FastCgi 与 PHP-fpm 之间的关系
- openssl 加解密
- 反射
- 钩子方法
- 查找插件
- opcode
- opcache使用
- opcache优化
- 分布式一致性hash算法
- 概念
- 哈希算法好坏的四个定义
- php实现
- java实现
- 数组
- jwt
- jwt简介
- 单点登录
- phpize
- GeoIP扩展
- php无法获得https网页内容的解决方案
- homestead运行的脚本
- Unicode和Utf-8转换
- php优化
- kafka
- fpm配置
- configure配置详解