Perl:$SIG {__ DIE__},eval {}和堆栈跟踪

前端之家收集整理的这篇文章主要介绍了Perl:$SIG {__ DIE__},eval {}和堆栈跟踪前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一段Perl代码有点像以下(强烈的简化):有一些级别的嵌套子程序调用(实际上是方法),一些内部函数执行自己的异常处理:
sub outer { middle() }

sub middle {
    eval { inner() };
    if ( my $x = $@ ) { # caught exception
        if (ref $x eq 'ARRAY') {
            print "we can handle this ...";
        }
        else {
            die $x; # rethrow
        }
    }
}

sub inner { die "OH NOES!" }

现在我想更改代码,以便它执行以下操作:

>打印一个完整的堆栈跟踪,每一个例外,“气泡”一直到最外层(子外部).具体来说,堆栈跟踪不应该停在“eval {}”的第一个级别.
>不需要改变任何内部层次的实现.

现在,我这样做的方法是在外部子程序中安装一个本地化的__DIE__处理程序:

use Devel::StackTrace;

sub outer {
    local $SIG{__DIE__} = sub {
        my $error = shift;
        my $trace = Devel::StackTrace->new;
        print "Error: $error\n","Stack Trace:\n",$trace->as_string;
    };
    middle();
}

[编辑:我犯了一个错误,上面的代码实际上并不像我想要的那样工作,它实际上绕过了中间子句的异常处理.所以我猜这个问题应该是真的:我想要甚么行为吗?]

这是完美的,唯一的问题是,如果我正确地理解文档,它依赖于明确不赞成的行为,即__DIE__处理程序即使是在“eval {}”内也被触发的事实,他们真的不应该. perlvar和perlsub都表示在以后版本的Perl中可能会删除此行为.

有没有另一种方法可以实现这一点,而不依赖于弃用的行为,还是保存依赖,即使文档说不另外?

解决方法

依靠文档所说的任何东西都不推荐使用是不安全的.在未来的版本中,行为可能(并且可能会)会发生变化.依靠不推荐的行为会将您锁定到今天运行的Perl版本中.

不幸的是,我没有看到符合你的标准的方法. “正确”的解决方案是修改内部方法调用Carp :: confess而不是死,并放置定制的$SIG {__ DIE__}处理程序.

use strict;
use warnings;
use Carp qw'confess';

outer();

sub outer { middle(@_) }

sub middle { eval { inner() }; die $@ if $@ }

sub inner { confess("OH NOES!") }
__END__
OH NOES! at c:\temp\foo.pl line 11
    main::inner() called at c:\temp\foo.pl line 9
    eval {...} called at c:\temp\foo.pl line 9
    main::middle() called at c:\temp\foo.pl line 7
    main::outer() called at c:\temp\foo.pl line 5

由于您还在死亡,您可能不需要将呼叫陷入inner(). (你不在你的例子中,你的实际代码可能有所不同)

在您的示例中,您尝试通过$@返回数据.你不能这样做使用

my $x = eval { inner(@_) };

代替. (我假设这只是简单的代码足以在这里发布的错误.)

原文链接:https://www.f2er.com/Perl/172503.html

猜你在找的Perl相关文章