开发者

How do I catch and rethrow an error in Perl?

Let's say I have a module Bar that is a subclass wrapper for module Foo. I want calls to Bar's methods to mimic Foo's exactly -- even down to fatal errors. So far, easy enough; I just call the SUPER method.


sub stuff {
    # Do stuff here

    SUPER::stuff(@_);

    # Do more stuff here
}

But, let's say that I want to catch, log, and rethrow any fatal errors SUPER::stuff() produces. First two steps are easy:


sub stuff {
    # Do stuff here

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

    # Do more stuff here
}

... but I don't know how to do the last part. How do I re-throw the error in such a way that the caller will be unable to distinguish between a call to Foo->stuff() and a call to Bar->stuff()? Can I just insert die $@ after the log statement and expect it to do开发者_如何学Python what I want, or are there nuances here that would likely get me into trouble?


The full code to safely eval/catch/log/rethrow in Perl can be a bit verbose.

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
}

You can use Try::Tiny sugested by mob to simplify:

sub stuff {
    # Do stuff here

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

    # Do more stuff here
}


What you're proposing will work. Perl doesn't have structured exceptions so the data in $@ is all the caller would get anyway.


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜