PHP下的异步尝试系列

  1. PHP下的异步尝试一:初识生成器
  2. PHP下的异步尝试二:初识协程
  3. PHP下的异步尝试三:协程的PHP版thunkify自动执行器
  4. PHP下的异步尝试四:PHP版的Promise
  5. [PHP下的异步尝试五:PHP版的Promise的继续完善]

生成器类


# http://php.net/manual/zh/class.generator.php
Generator implements Iterator {
/* Methods */
//获取迭代器当前值
public mixed current ( void )
//获取迭代器当前值
public mixed getReturn ( void )
//返回当前产生的键
public mixed key ( void )
//生成器从上一次yield处继续执行
public void next ( void )
//重置迭代器
public void rewind ( void )
//向生成器中传入一个值
public mixed send ( mixed $value )
//向生成器中抛入一个异常
public mixed throw ( Throwable $exception )
//检查迭代器是否被关闭
public bool valid ( void )
//迭代器序列化时执行的方法
public void __wakeup ( void )
}

生成生成器

尝试实例化类


$gen = new Generator(); # 我们发现不能直接手动实例化
# output
PHP Fatal error: Uncaught Error: The "Generator" class is reserved for internal use and cannot be manually instantiated in /web/www/sxx_admin3/src/cache/test/amphp/gen3.php:8

尝试function方式


function gen($max)
{
for ($i=0; $i<$max; $i++) {
yield $i;
}
} $gen = gen(5); # success
# 成功,我们只需要在普通函数方法里yield即可成了生成器

理解php的生成器

其实各语言都有生成器,比如python,go等

生成器迭代foreach

被代码将演示valid, getReturn


function gen($max)
{
for ($i=0; $i<$max; $i++) {
yield $i;
} return $max;
} $gen = gen(5); foreach ($gen as $val) {
var_dump($val);
} //如果已经迭代完成,获取返回值
// php7 支持
// valid 判断当前迭代器是否迭代完成
// getReturn 返回迭代器的返回值
if (version_compare(PHP_VERSION, '7.0.0') >= 0 && !$gen->valid()) {
var_dump($gen->getReturn());
}

带key值的生成器迭代foreach

迭代器返回值可以带key和value,类似


function gen($max)
{
for ($i=0; $i<$max; $i++) {
yield $i => $i+1;
} return $max;
} $gen = gen(5); //var_dump($gen->key());
//var_dump($gen->current()); foreach ($gen as $key=>$val) {
var_dump($key . "=>" . $val);
} # output
string(4) "0=>1"
string(4) "1=>2"
string(4) "2=>3"
string(4) "3=>4"
string(4) "4=>5"

生成器迭代手动迭代

本代码将演示rewind, next, send方法


function gen($max)
{
for ($i=0; $i<$max; $i++) {
// 此处的(yield $i)在php7以后版本可省略
$res = (yield $i);
var_dump($res);
} return $max;
} $gen = gen(10); // 可不调用,隐式调用
// 如果迭代开始后不能再rewind(即使用了next或send后)
$gen->rewind(); // 打印获取到当前生成器的值
var_dump("1::" . $gen->current()); //output: string(4) "1::0" // 下面2句代码执行,将返回错误
// $gen->next();
// $gen->rewind(); //继续执行,知道遇到下一个yield
$gen->next();
var_dump("2::" . $gen->current()); //output: string(4) "2::1"
$gen->next();
var_dump("3::" . $gen->current()); //output: string(4) "3::2" // send传null值等同于调用next(本方法尝试来自python的迭代器,成功)
$gen->send(null);
var_dump("4::" . $gen->current()); //output: string(4) "4::3" // send传值会也会继续执行
$gen->send(100);
var_dump("5::" . $gen->current()); //output: string(4) "5::4" //如果已经迭代完成,获取返回值
// php7 支持
if (version_compare(PHP_VERSION, '7.0.0') >= 0 && !$gen->valid()) {
var_dump($gen->getReturn());
} # output:
string(4) "1::0"
NULL
string(4) "2::1"
NULL
string(4) "3::2"
NULL
string(4) "4::3"
int(100)
string(4) "5::4" # 我们先不去理会gen里var_dump输出的NULL或int(100)
# 我们先去理解每次next后current可以获取到当前yield的值即可

尝试理解send输出


function gen($max)
{
for ($i=0; $i<$max; $i++) {
$res = (yield $i);
var_dump($res);
} return $max;
} $gen = gen(10); var_dump("1::" . $gen->current()); $gen->send(222);
var_dump("2::" . $gen->current()); $gen->send(333);
var_dump("3::" . $gen->current()); $gen->send(null);
var_dump("4::" . $gen->current()); # output:
string(4) "1::0"
int(222)
string(4) "2::1"
int(333)
string(4) "3::2"
int(444)
string(4) "4::3" # send和next
# next() => current = yield值
# send(val) $rs = yield 表达式执行 = val; //send这样理解即可
# 在当前某个yield处时send,当前yield表达式处返回,如果没有变量接收,那么继续下一个yield处返回
$rs = (yield somethind_to_do(...) );
^ |-------------------|
| yield值
| |----------------------------|
| yield 表达式
yield表达式结果 # 执行顺序流程类似
$res = (yield 1); // <- var_dump("1::" . $gen->current()); 第一步到yield返回 var_dump($res); // <- $gen->send(222); 第二步send:222后,继续往下走$res=222 然后var_dump($res), 然后到了yield 2
$res = (yield 2); // <- var_dump("2::" . $gen->current()); 打印当前的值2 var_dump($res); // <- $gen->send(333); 第三步send:333后,继续往下走$res=333 然后var_dump($res), 然后到了yield 3
$res = (yield 3); // <- var_dump("3::" . $gen->current()); var_dump($res); // <- $gen->send(null); 第二步send:null后,继续往下走$res=null 然后var_dump($res), 然后到了yield 4
$res = (yield 4); // <- var_dump("4::" . $gen->current());

生成器throw抛出错误


# 内部定义异常并返回,外部接收
function gen() {
echo "Gen 开始\n";
yield new Exception('内部定义异常');
echo "Gen 结束\n";
} $gen = gen();
try {
throw $gen->current();
} catch (\Exception $e) {
echo "外部捕获异常:" . $e->getMessage() . PHP_EOL;
} $gen->send("123"); # output:
Gen 开始
外部捕获异常:内部定义异常
Gen 结束 # 内部接收send传入的异常,然后直接throw,外部接收
function gen() {
echo "Gen 开始\n";
throw (yield new Exception('内部定义异常'));
echo "Gen 结束\n";
} $gen = gen();
try {
throw $gen->current();
} catch (\Exception $e) {
echo "外部捕获异常:" . $e->getMessage() . PHP_EOL;
} try {
$gen->send(new \Exception("外部定义异常"));
} catch (\Exception $e) {
echo "外部捕获异常:" . $e->getMessage() . PHP_EOL;
} # output
Gen 开始
外部捕获异常:内部定义异常
外部捕获异常:外部定义异常 #
function gen() {
echo "Gen 开始\n";
try {
yield new Exception('内部定义异常');
} catch (Exception $e) {
echo "内部捕获异常:" . "Exception: {$e->getMessage()}\n";
} echo "Gen 结束\n";
} $gen = gen();
try {
throw $gen->current();
} catch (\Exception $e) {
echo "外部捕获异常:" . $e->getMessage() . PHP_EOL;
} // 注意这里是throw方法,相当于
// $gen->send(new \Exception("外部定义异常"));
// throw yield (yield接收 = new \Exception("外部定义异常"))
$gen->throw(new \Exception("外部定义异常")); #output
Gen 开始
外部捕获异常:内部定义异常
内部捕获异常:Exception: 外部定义异常
Gen 结束

总结


初识我们只需要先理解next和send即可
next->让我们可以主动自动执行迭代器
send->可以让我们的迭代器实现双向通信,改变执行体流程顺序
后续我们会介绍使用场景和Co自动执行体等

文章更名记录


2018.09.20: [PHP下的生成器尝试一:初识PHP下的生成器] -> [PHP下的异步尝试一:初识生成器]

原文地址:https://segmentfault.com/a/1190000016444494

PHP下的异步尝试一:初识生成器的更多相关文章

  1. PHP下的异步尝试二:初识协程

    PHP下的异步尝试系列 如果你还不太了解PHP下的生成器,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunkify ...

  2. PHP下的异步尝试四:PHP版的Promise

    PHP下的异步尝试系列 如果你还不太了解PHP下的生成器和协程,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunk ...

  3. PHP下的异步尝试三:协程的PHP版thunkify自动执行器

    PHP下的异步尝试系列 如果你还不太了解PHP下的生成器和协程,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunk ...

  4. 刚刚研究了下ipv6,尝试配置内网VPS的IPv6地址

    刚刚研究了下ipv6,尝试配置内网VPS的IPv6地址是3台设备,分别是客户机Windows系统.核心交换机.PPPoE拨号的路由器 第一步:在PPPoE拨号的路由器上面查看ppp0拨号的地址 ifc ...

  5. PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)

    源码地址:https://github.com/Tinywan/PHP_Experience 测试环境配置: 环境:Windows 7系统 .PHP7.0.Apache服务器 PHP框架:ThinkP ...

  6. 初探.net framework 下的异步多线程

    初探.net framework 下的异步多线程 目录 1.多线程的出现条件 2.Thread和ThreadPool的相关Api及用法 3.Task和Parallel的相关Api及用法 4.Async ...

  7. 【神经网络与深度学习】【CUDA开发】caffe-windows win32下的编译尝试

    [神经网络与深度学习][CUDA开发]caffe-windows win32下的编译尝试 标签:[神经网络与深度学习] [CUDA开发] 主要是在开发Qt的应用程序时,需要的是有一个使用的库文件也只是 ...

  8. javascript异步编程之generator(生成器函数)与asnyc/await语法糖

    Generator 异步方案 相比于传统回调函数的方式处理异步调用,Promise最大的优势就是可以链式调用解决回调嵌套的问题.但是这样写依然会有大量的回调函数,虽然他们之间没有嵌套,但是还是没有达到 ...

  9. python初识生成器 迭代器

    生成器 带有 yield 的函数在 Python 中被称之为 generator(生成器) def xragns(): #定义函数生成器 print('小伙') yield ('好') #加上yiel ...

随机推荐

  1. 训练1-D

    把一个字符三角形掏空,就能节省材料成本,减轻重量,但关键是为了追求另一种视觉效果.在设计的过程中,需要给出各种花纹的材料和大小尺寸的三角形样板,通过电脑临时做出来,以便看看效果. Input 每行包含 ...

  2. 【SPOJ 104】HIGH - Highways (高斯消元)

    题目描述 In some countries building highways takes a lot of time- Maybe that's because there are many po ...

  3. 基于Tags的简单内容推荐的实现

    原来为了简单方便,自己小网站上的文章页的相关内容推荐就是从数据库里随机抽取数据来填充一个列表,所以一点相关性都没有,更本没有办法引导用户去访问推荐内容. 算法选择 如何能做到相似内容的推荐呢,碍于小网 ...

  4. Python面向对象之静态方法、静态方法与类方法

    静态属性: 类调用函数属性时,需要先将类实例化,再将实例作为函数属性传入:类的实例调用函数属性时需要在后面加括号. class Building: def __init__(self, name, o ...

  5. tomcat work目录的作用就是编译每个项目里的jsp文件为java文件如果项目没有jsp页面则这个项目文件夹为空

    最近发现,很多网友喜欢把tomcat的work目录里的东西叫做缓存,其实那不是很恰当,work目录只是tomcat的工作目录,也就是tomcat把jsp转换为class文件的工作目录,这也正是为什么它 ...

  6. Server Tomcat v8.0 Server at localhost was unable to start within 45 seconds. If the server requires

    Server Tomcat v8.0 Server at localhost was unable to start within 45 seconds. If the server requires ...

  7. Openwrt 软件安装源

    进入http://downloads.openwrt.org/barrier_breaker/14.07/站点找到符合处理器型号的软件源.參考下图: watermark/2/text/aHR0cDov ...

  8. NSAttributedString编程

    - (void)viewDidLoad {     [super viewDidLoad];          NSMutableAttributedString *attributedString ...

  9. 均匀分布(uniform distribution)期望的最大似然估计(maximum likelihood estimation)

    maximum estimator method more known as MLE of a uniform distribution [0,θ] 区间上的均匀分布为例,独立同分布地采样样本 x1, ...

  10. 【POJ 2828】Buy Tickets

    [题目链接] http://poj.org/problem?id=2828 [算法] 离线用线段树维护序列即可 [代码] #include <algorithm> #include < ...