这篇文章是我对PHP异步编程的研究总结。对于相当一部分PHPer来说,他们可能并不知道Generator,或者对Generator的流程不是很熟悉。因为Generator让程序不再是顺序的。鉴于本人水平有限,如有不同意见,还望指点指点,万分感谢!PHP中的异常处理从PHP5开始,PHP为我们提供了异常处理的trycatch。当我们使用catch捕获异常时,就会执行后续代码。让我们看看下面的例子。try{thrownewException('e');}catch(Exception$e){echo$e->getMessage();}//输出:e}echo2;//output:2如果我们没有捕获异常,那么下面的代码将不会被执行。抛出新的异常('e');//抛出异常echo2;//不是executeGenerator的throw方法在PHP中,Generator提供了throw方法来抛出异常。用法与普通异常相同,只是将throw关键字改为方法调用。函数gen(){产量0;产量1;产量2;产量3;}$gen=gen();$gen->throw(newException('e'));//抛出异常var_dump($gen->valid());//输出:falsecho2;//不执行同样的,我们可以通过trycatch来捕获这个异常。尝试{$gen->throw(newException('e'));}catch(Exception$e){echo$e->getMessage();//输出:e}var_dump($gen->valid());//输出:falsecho2;//output:2我们可以看到,当我们使用throw抛出异常时,当前generator的有效值变成了false。但是考虑下面的情况,当我们在外面调用throw方法后在生成器函数中捕获到异常会发生什么?让我们看看下面的例子。函数gen(){产量0;尝试{产量;}catch(Exception$e){echo$e->getMessage();//输出:e}yield2;产量3;}$gen=gen();$gen->next();//达到捕获异常的程度$gen->throw(newException('e'));var_dump($gen->valid());//输出:trueecho2;//output:2我们在生成器函数中捕获throw方法抛出的异常后,生成器仍然有效。但是如果像之前那样调用throw方法,那么生成器就完蛋了。在生成器函数中抛出异常functiongen(){yield0;抛出新的异常('e');产量2;产量3;}$gen=gen();$gen->next();$gen->current();//抛出异常var_dump($gen->valid());//输出:falsecho2;//不执行我们之前看到的是调用throw方法抛出异常。然后在generatorfunction里面,在generatorfunction里面没有捕获异常,抛出异常,结果是一样的。另外,如果在生成器函数中捕获到异常,则与前面的示例相同。理解了上面的例子之后,我们要考虑如果我们有嵌套的生成器会发生什么。嵌套生成器当我们在一个生成器函数中产生另一个生成器函数时,它就变成了一个嵌套生成器。让我们看看下面的例子。函数subGen(){产量1;抛出新的异常('e');产量4;}函数gen(){产量0;产量子代();产量2;产量3;}$gen=gen();$gen->next();$gen->current()->next();//抛出异常echo2;//不执行对于嵌套生成器,如果在子生成器中抛出异常,那么如果没有捕获到这个异常,就会逐步往上抛,直到结束。我们刚才试了一下,抛出异常后,valid的返回值变成了false。那么在嵌套生成器中也是一样的吗?我们捕获异常,以便程序可以继续执行。让我们看看下面的例子。函数subGen(){产量1;抛出新的异常('e');产量4;}函数gen(){产量0;产量子代();产量2;产量3;}$gen=gen();$gen->next();try{$gen->current()->next();}catch(Exceprion$e){echo$e->getMessage();//输出:e}var_dump($gen->valid());//输出:trueecho2;//output:2所以,当子生成器在迭代过程中抛出异常并被正常捕获时,那么父生成器将不会受到影响,valid的返回值仍然为true。总结关于生成器的异常处理,这里总结一下。在generator中抛出异常,或者使用throw方法抛出异常,则generator的迭代结束,valid变为false;在生成器中抛出异常,在迭代过程中异常会被捕获,生成器的迭代仍然会结束,valid仍然会变为false;如果在generator中抛出异常,会在generator中捕获并处理,generator的迭代不会结束,valid会返回true;在嵌套的生成器中,如果子生成器抛出异常,只会影响子生成器,不会影响父生成器。Postscriptyield为我们提供了使用PHP实现半协程的工具。最近一直在研究使用yield实现半协程,而在这个过程中,异常的处理非常重要。但是yield的运行方式决定了异常处理比较难理解。所以我花了几天时间尝试了各种可能性,得出了这些结论。当然,由于本人水平有限,如有错误,还望指点指点,万分感谢。
