答案 0 :(得分:25)
Perl的eval
有两种形式,字符串eval和block eval。 String eval调用编译器来执行源代码。块eval将已编译的代码包含在一个包装器中,该包装器将捕获die
异常。 (字符串eval也会捕获die
异常,以及任何编译错误。)
Try :: Tiny仅适用于eval的块形式,但以下内容适用于两种形式。
每次拨打eval
时,都会更改$@
的值。如果eval成功或者eval捕获到错误,它将为''
。
这意味着每次调用eval时,都会清除以前的错误消息。 Try::Tiny
为您本地化$@
变量,以便成功的eval不会清除先前失败的eval的消息。
另一个缺陷来自于使用$@
作为检查以确定eval是否成功。常见的模式是:
eval {...};
if ($@) {
# deal with error here
}
这取决于两个假设,首先是任何错误消息$@
可以包含的是一个真值(通常为真),并且eval块和if语句之间没有代码。
当然后者当然是正确的,但是如果eval块创建了一个对象,并且该对象在eval失败后超出了范围,那么将在{{1}之前调用该对象的DESTROY
方法声明。如果if
恰好在没有本地化DESTROY
的情况下调用eval并且成功,那么当您的$@
语句运行时,if
变量将被清除。
解决这些问题的方法是:
$@
逐行分开,my $return = do {
local $@;
my $ret;
eval {$ret = this_could_fail(); 1} or die "eval failed: $@";
$ret
};
为local $@
块创建一个新的$@
,以防止破坏以前的值。 do
将是评估代码的返回值。在eval块中,my $ret
被分配给,然后块返回$ret
。这样,无论如何,如果eval成功,它将返回true,如果失败则返回false。在失败的情况下,由您决定该怎么做。上面的代码就好了,但你可以很容易地使用eval块的返回值来决定运行其他代码。
由于上述咒语有点乏味,因此容易出错。使用像1
这样的模块可以使您免受这些潜在错误的影响,而每个eval会增加一些函数调用。了解如何正确使用eval非常重要,因为如果必须使用字符串eval,Try::Tiny
将无法帮助您。
答案 1 :(得分:11)
问题在Try::Tiny documentation中解释。简而言之,它们是:
答案 2 :(得分:6)
除了上面的答案,我还会添加......
$SIG{__DIE__}
处理程序的影响。eval BLOCK
和eval STRING
,因为它们似乎做同样的事情,但其中一个是安全漏洞。尝试:: Tiny有自己的陷阱,最大的问题是虽然它看起来像一个块,但它实际上是一个子程序调用。这意味着:
eval {
...blah blah...
return $foo;
};
和此:
try {
...blah blah...
return $foo;
};
不要做同样的事情。这些都列在CAVEATS section of the Try::Tiny docs中。也就是说,我推荐它eval
。
答案 3 :(得分:0)
在X11上使用eval功能可能仍然无法保持活动状态。
代码就像
eval {
@win_arrays = GetWindowsFromPid($pid);
};
该脚本将退出
X请求失败的错误:...