如何检测是否在eval中运行Perl代码?

oal*_*ers 6 perl

我有一个使用@INC钩子的模块,并试图安装丢失的模块,因为它们是used.我不希望这种行为在内部触发eval.我目前的尝试是:

return
    if ( ( $caller[3] && $caller[3] =~ m{eval} )
    || ( $caller[1] && $caller[1] =~ m{eval} ) );
Run Code Online (Sandbox Code Playgroud)

这是我在一些实验中用调用堆栈的结果,但它没有捕获所有内容,例如HTTP :: Tinyish中的代码:

sub configure_backend {
    my($self, $backend) = @_;
    unless (exists $configured{$backend}) {
        $configured{$backend} =
          eval { require_module($backend); $backend->configure };
    }
    $configured{$backend};
}

sub require_module {
    local $_ = shift;
    s!::!/!g;
    require "$_.pm";
}
Run Code Online (Sandbox Code Playgroud)

也许我只需要遍历调用堆栈的每个级别,直到我达到eval或超出级别.有没有更好或更简单的方法来判断代码是否在eval没有遍历调用堆栈的情况下被包装?


在这个问题上验尸:

  • 正如多张海报所暗示的那样,这基本上是一个坏主意
  • $^S从技术上讲,这是一种正确的方法,但它不会让你知道你是否在一个eval被称为堆栈中更高的地方
  • 使用正则表达式+ Carp::longmess()似乎是最简洁的方法来解决这个问题
  • 知道代码是否在一个内部运行eval可能对信息目的有所帮助,但由于这可能由于许多不同的原因而发生,因此很难推断它为什么会发生
  • 无论如何,这是一个有趣的练习.我感谢所有贡献者的有益投入

Sch*_*ern 5

如果$^S为 true,则代码位于eval.

sub foo { print $^S }
eval { foo() };  # 1
foo();           # 0
Run Code Online (Sandbox Code Playgroud)


mob*_*mob 5

Carp::longmess 在一次调用中遍历堆栈,如果这样可以使事情变得更容易

return if Carp::longmess =~ m{^\s+eval }m
Run Code Online (Sandbox Code Playgroud)