【问题标题】:protecting global variables during eval in Test::More在 Test::More 中的 eval 期间保护全局变量
【发布时间】:2014-01-25 17:44:59
【问题描述】:

我滚动浏览了 Test::More 的代码,因为我想看看 use_okrequire_ok 是如何实现的(以及为什么 Ovid 不喜欢它们)。我来到_eval 子例程,它包含一些我不完全理解的特殊逻辑,用于在eval 调用期间保护变量。我从Try::Tiny 的文档中了解到处理$@ 有多么困难。但是,我不明白$!$SIG{__DIE__} 的处理方式(下面逐字复制):

# Work around oddities surrounding resetting of $@ by immediately
# storing it.
my( $sigdie, $eval_result, $eval_error );
{
    local( $@, $!, $SIG{__DIE__} );    # isolate eval
    $eval_result = eval $code;              ## no critic (BuiltinFunctions::ProhibitStringyEval)
    $eval_error  = $@;
    $sigdie      = $SIG{__DIE__} || undef;
}
# make sure that $code got a chance to set $SIG{__DIE__}
$SIG{__DIE__} = $sigdie if defined $sigdie;

$SIG{__DIE__}的处理和RT #34065有关,但还是没搞懂。为什么有必要在最后一行再次设置变量,因为它应该总是在块的最后一行设置?如果这些行的全部意义在于将变量设置为在eval 调用中的任何内容,那么为什么必须首先将其本地化?

另外,如果使用 eval 而不破坏错误变量意味着本地化 $@$!,我们是否也不必本地化 $?

【问题讨论】:

    标签: perl error-handling eval test-more


    【解决方案1】:

    在我看来,$sigdie 是为了明确允许评估代码设置 $SIG{__DIE__},同时不允许任何外部设置的处理程序在评估期间生效。

    所以本地化抑制了外部值,但需要在块结束之前保存任何设置值,并在块之后将其设置为现在未本地化的版本。

    我假设 $! 是本地化的,但不是 $?$^E 等,出于实际原因(也就是说,我猜人们抱怨 $! 发生了变化,但没有其他任何事情)。

    【讨论】:

    • 为什么要禁止调用者明确设置的$SIG{__DIE__} 生效?
    • 因为 perl 中的早期设计决策不佳,__DIE__ 处理程序会被任何异常触发,即使是被 eval 捕获的异常。因为测试框架正在处理一些异常,它们不应该也影响框架之外的代码。
    猜你喜欢
    • 1970-01-01
    • 2013-02-07
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 2015-03-19
    • 2015-03-08
    • 1970-01-01
    • 2017-08-10
    相关资源
    最近更新 更多