如何在Perl中捕获并重新抛出错误?

Bla*_*ppo 4 perl

假设我有一个模块Bar,它是模块Foo的子类包装器.我希望调用Bar的方法来模仿Foo - 甚至是致命的错误.到目前为止,很容易; 我只是称之为SUPER方法.


sub stuff {
    # Do stuff here

    SUPER::stuff(@_);

    # Do more stuff here
}
Run Code Online (Sandbox Code Playgroud)

但是,让我们说我想抓住,记录并重新抛出任何致命的错误SUPER::stuff().前两个步骤很简单:


sub stuff {
    # Do stuff here

    eval {
        SUPER::stuff(@_);
    };
    $@ and log("Naughty, naughty: $@");

    # Do more stuff here
}
Run Code Online (Sandbox Code Playgroud)

......但我不知道怎么做最后一部分.如何以这样一种方式重新抛出错误,即调用者无法区分调用Foo->stuff()和调用Bar->stuff()?我可以die $@在日志声明之后插入并期望它能够做我想要的,或者这里有细微差别可能会让我遇到麻烦吗?

Ven*_*tsu 5

在Perl中安全地eval/catch/log/rethrow的完整代码可能有点冗长.

sub stuff {
    # Do stuff here

    local $@; # don't reset $@ for our caller.
    my $eval_ok = eval { # get the return from eval, it will be undef if the eval catches an error.
        SUPER::stuff(@_);
        1; # return 1 (true) if there are no errors caught.
    };
    if (!$eval_ok) { # don't trust $@ it might have been reset as the eval unrolled.
        my $error = $@ || 'unknown error'; # copy $@ incase write_log resets $@, or is later changed to cause it to reset $@.
        write_log("Naughty, naughty: $error");
        die $error; # after all that we can rethrow our error.
    }

    # Do more stuff here
}
Run Code Online (Sandbox Code Playgroud)

您可以使用尝试::微小的暴徒sugested简化:

sub stuff {
    # Do stuff here

    try {
        SUPER::stuff(@_);
    } catch {
        my $error = $_;
        write_log("Naughty, naughty: $error");
        die $error;
    }

    # Do more stuff here
}
Run Code Online (Sandbox Code Playgroud)