本文是我在研究 PHP 异步编程时的总结。对于至关多的 PHPer 来讲,可能都不知道 Generator,或者对 Generaotr 的流程不是很熟悉。由于 Generator 使得程序再也不是顺序的。鉴于本人的水平有限,若是有不一样意见,还望指点一二,不胜感激!php
从 PHP 5 开始,PHP 为咱们提供了 try catch 来进行异常处理。当咱们使用 catch 将异常捕获,那么一场后续的代码就会执行。咱们看看下面的例子。编程
try { throw new Exception('e'); } catch (Exception $e) { echo $e->getMessage(); // output: e } echo 2; // output: 2
若是咱们没有将异常捕获,那么后面的代码就不会执行了。异步
throw new Exception('e'); // throw an exception echo 2; // not execute
在 PHP 中,Generator 提供了 throw
方法来抛出异常。用法和普通的异常同样,只不过把 throw
关键字改为了方法调用。异步编程
function gen() { yield 0; yield 1; yield 2; yield 3; } $gen = gen(); $gen->throw(new Exception('e')); // throw an exception var_dump($gen->valid()); // output: false echo 2; // not execute
一样的,咱们能够这个异常捕获,经过 try catch 来进行。函数
try { $gen->throw(new Exception('e')); } catch (Exception $e) { echo $e->getMessage(); // output: e } var_dump($gen->valid()); // output: false echo 2; // output: 2
咱们能够看到,当咱们使用 throw 抛出异常后,当前的生成器的 valid 变成了 false。可是考虑下面一种状况,当咱们在外面调用 throw 方法后,在生成器函数中捕获异常,会发生什么呢?咱们来看下面的例子。工具
function gen() { yield 0; try { yield; } catch (Exception $e) { echo $e->getMessage(); // output: e } yield 2; yield 3; } $gen = gen(); $gen->next(); // reach the point of catching exception $gen->throw(new Exception('e')); var_dump($gen->valid()); // output: true echo 2; // output: 2
当咱们在生成器函数捕获来自 throw 方法抛出的异常后,生成器依然是 valid 的。可是若是像刚才同样只是在调用 throw 方法,那么生成器就结束了。code
function gen() { yield 0; throw new Exception('e'); yield 2; yield 3; } $gen = gen(); $gen->next(); $gen->current(); // throw an exception var_dump($gen->valid()); // output: false echo 2; // not execute
以前咱们看到的是调用 throw 方法来抛出异常。那么在生成器函数中,抛出一个异常而没有在生成器函数中捕获,结果也都是同样的。一样的,若是在生成器函数中捕获了异常,那么就和以前的例子同样了。协程
在理解了上面的例子以后,咱们就要考虑一下,若是有嵌套的生成器,会发生什么了。get
当咱们在一个生成器函数中,yield
了另一个生成器函数以后,就会变成嵌套生成器。咱们来看下面的例子。io
function subGen() { yield 1; throw new Exception('e'); yield 4; } function gen() { yield 0; yield subGen(); yield 2; yield 3; } $gen = gen(); $gen->next(); $gen->current()->next(); // throw an exception echo 2; // not execute
对于嵌套的生成器来讲,若是子生成器中抛出了异常,那么在没有捕获这个异常的状况下,会一级一级向上抛出,直到结束。
刚才咱们尝试了,在抛出异常以后,valid 的返回值变成了 false。那么在嵌套生成器中,是否是也是这样呢?咱们把异常捕获,使程序可以继续执行下去,来看下面这个例子。
function subGen() { yield 1; throw new Exception('e'); yield 4; } function gen() { yield 0; yield subGen(); yield 2; yield 3; } $gen = gen(); $gen->next(); try { $gen->current()->next(); } catch (Exceprion $e) { echo $e->getMessage(); //output: e } var_dump($gen->valid()); // output: true echo 2; // output: 2
因此,当子生成器抛出异常后在迭代的过程当中被正常地捕获,那么,父生成器便不会受到影响,valid 的返回值依然是 true
。
关于生成器的异常处理,这里来进行一下总结。
false
;false
;true
;yield 为咱们提供了使用 PHP 实现半协程的工具。最近在研究使用 yield 实现半协程,而这个过程当中,对异常的处理,是很是重要的。可是 yield 的运行方式决定了异常处理比较难以理解。因而我花了几天的时间,尝试了各类可能,得出来的这些结论。固然因为本人水平有限,若有错误,还望指点一二,不胜感激。