开发者

What's the most elegant way to catch a signal in Perl?

I have 2 开发者_StackOverflowlines near one another in a Perl script that could throw a __WARN__. If the first one throws, then I want to just return from the function and not try to continue.

I know how to set up a handler before both lines so I can report the error etc:

local $SIG{__WARN__} = sub {
  my $e = shift;
  # log the error etc.
  return;
};
# possibly warning-resulting line 1
# possibly warning-resulting line 2

But then this happens for both lines. I'd rather it just caught the first instance and returned from the function. But the return in that handler only returns the handler, not the outer function.

Is there a way to return from the function when handling a signal?


Wrap the two lines in separate functions, and have the first return a status indicating that the calling function should return. The separate functions can deal with the warnings as you need - possibly using the same function to do the same logging.

sub wrap_line_1
{
    local $SIG{__WARN__} = ...;
    ...do line 1...
    return ($warning_fired ? 1 : 0);
}

sub wrap_line_2
{
    local $SIG{__WARN__} = ...;
    ...do line 2...
    return;
}


...calling code...
wrap_line_1() and return;
wrap_line_2();
...


No, you can't force the caller to return. (Well, I'm sure you can, with the right black magic XS incantation. But don't!)

This seems like a misguided design; warnings aren't supposed to be fatal errors, and certainly shouldn't be used like this.


You can die() in your handler and catch this in an eval as shown below:

use 5.12.0;

local $SIG{__WARN__} = sub {
  my $e = shift;
  # log the error etc.
  die "$e";
};

func(undef);
func('honk');

sub func {
    my $foo = shift;

    eval {
       my $bar = "a $foo";
       say "$bar";
    };
    if ($@) {
       die $@ unless $@ =~ /^Use of uninitialized value/;
    }
    return;
}

You probably, though, want to check directly if the warning could happen and simply return:

sub func {
  my $foo = shift;
  return unless defined($foo);
  ...; # use $foo fine
}


Just throw an exception and catch and return in the caller.

Make the handler return a value and check it to return in the if statement after the eval.

Actually you don't even have to return a value from the handler because it's not deciding whether to return -- you always return when you catch.

Specifically:

# We're in the caller now
eval{
    local $SIG{__WARN__} = sub {
        my $e = shift;
        # log the error etc.
        die MyWarnException->new("This is an exception.");
    };

    # Offending statements go here
    do_things();

};
if( $@ && $@->isa('MyWarnException')){
    return;
}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜