资讯专栏INFORMATION COLUMN

Generator 的异常处理

Bmob / 1716人阅读

摘要:的方法在中,提供了方法来抛出异常。总结关于生成器的异常处理,这里来进行一下总结。最近在研究使用实现半协程,而这个过程中,对异常的处理,是非常重要的。但是的运行方式决定了异常处理比较难以理解。

本文是我在研究 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
Generator 的 throw 方法

在 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 方法,那么生成器就结束了。

在生成器函数中抛出异常
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 方法来抛出异常。那么在生成器函数中,抛出一个异常而没有在生成器函数中捕获,结果也都是一样的。同样的,如果在生成器函数中捕获了异常,那么就和之前的例子一样了。

在理解了上面的例子之后,我们就要考虑一下,如果有嵌套的生成器,会发生什么了。

嵌套生成器

当我们在一个生成器函数中,yield 了另外一个生成器函数之后,就会变成嵌套生成器。我们来看下面的例子。

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

总结

关于生成器的异常处理,这里来进行一下总结。

在生成器中抛出一个异常,或者使用 throw 方法抛出一个异常,那么,生成器的迭代便会结束,valid 变成 false

在生成器中抛出一个异常,迭代过程中对异常进行捕获,生成器的迭代依然会结束,valid 依然会变成 false

在生成器中抛出一个异常,在生成器中将其捕获处理,生成器的迭代不会结束,valid 会返回 true

在嵌套的生成器中,如果子生成器抛出了异常,只会对子生成器产生影响,不会对父生成器产生影响。

后记

yield 为我们提供了使用 PHP 实现半协程的工具。最近在研究使用 yield 实现半协程,而这个过程中,对异常的处理,是非常重要的。但是 yield 的运行方式决定了异常处理比较难以理解。于是我花了几天的时间,尝试了各种可能,得出来的这些结论。当然由于本人水平有限,如有错误,还望指点一二,不胜感激。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/25663.html

相关文章

  • 高质量 Node.js 微服务编写和部署

    摘要:编写代码的开发人员必须负责代码的生产部署。构建和部署链需要重大更改,以便为微服务环境提供正确的关注点分离。该对象会在之后的时被这时的回调函数会被调用,并输出。微服务部署及集成部署微服务时有一个原则一个容器中只放一个服务,可以使用编 前几天在微信群做的一次分享,整理出来分享给大家,相关代码请戳 https://github.com/Carrotzpc/docker_web_app sho...

    szysky 评论0 收藏0
  • 高质量 Node.js 微服务编写和部署

    摘要:编写代码的开发人员必须负责代码的生产部署。构建和部署链需要重大更改,以便为微服务环境提供正确的关注点分离。该对象会在之后的时被这时的回调函数会被调用,并输出。微服务部署及集成部署微服务时有一个原则一个容器中只放一个服务,可以使用编 前几天在微信群做的一次分享,整理出来分享给大家,相关代码请戳 https://github.com/Carrotzpc/docker_web_app sho...

    Michael_Ding 评论0 收藏0
  • 《Node.js设计模式》基于ES2015+回调控制流

    摘要:以下展示它是如何工作的函数使用构造函数创建一个新的对象,并立即将其返回给调用者。在传递给构造函数的函数中,我们确保传递给,这是一个特殊的回调函数。 本系列文章为《Node.js Design Patterns Second Edition》的原文翻译和读书笔记,在GitHub连载更新,同步翻译版链接。 欢迎关注我的专栏,之后的博文将在专栏同步: Encounter的掘金专栏 知乎专栏...

    LiuRhoRamen 评论0 收藏0
  • es6 Generators详解

    摘要:每个任务必须显式地挂起自己,在任务切换发生时给予它完全的控制。在这些尝试中,数据经常在任务之间共享。但由于明确的暂停,几乎没有风险。 翻译自 github 概述 什么是generators? 我们可以把generators理解成一段可以暂停并重新开始执行的函数 function* genFunc() { // (A) console.log(First); yi...

    zhaot 评论0 收藏0
  • 异步编程解决方案 - generator

    摘要:异步编程解决方案事件发布订阅模式订阅,发布事件监听是一种高阶函数的应用,通过事件可以把内部数据传递给外部的调用者,编程者可以不用关心组件内部如何执行,只需关注在需要的事件点上即可。 异步编程难点 异常处理 在处理异常时经常用try/catch/final语句块进行异常捕获,但是这种异常捕获对异步编程并不是用 function async(callback) { process....

    AbnerMing 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<