perlcritic: eval "require $module";

perlcritic: eval "require $module";

在挖掘一些旧源代码时,我看到了以下内容:

my $module = $some{module};
eval "require $module";
die "Bad module\n$@" if $@;

虽然我理解代码的作用,但它会尝试 "require" 一个模块并在不成功时死掉 - perlcritic 抱怨它

Expression form of "eval" at line 331, column 13. See page 161 of PBP. (Severity: 5)

可惜我没有PBP的书,所以想知道上面的正确方法是什么...

此外,在同一来源中发现:

sub test_repo_file {
    my($self, $repo, $test) = @_;
    my $abspath = repo_abs_path($repo);
    return "eval -$test $abspath";
}

这里不明白是什么解决了 "eval",perlcritic 再次抱怨 "string eval"...

有人可以解释一下 "string eval" 的基本要点以及如何正确地写上面的内容吗?

运行 perlcritic --verbose '%d\n'也会给你解释:

The string form of `eval' is recompiled every time it is executed, whereas the block form is only compiled once. Also, the string form doesn't give compile-time warnings.

   eval "print $foo";        # not ok
   eval {print $foo};        # ok

适用于第一种情况

第二种情况没有为我生成任何消息。不如

return eval "-$test $abspath"

您不能在此处使用块评估。您应该验证 $test 确实包含它应该包含的内容

$test =~ /^[a-z]$/i

并避免计算 $abspath:

eval "-$test $abspath"

如果您同意,可以添加

## no critic

到行尾。

很少有用户必须使用 eval EXPR。大多数时候,它在不应该使用时用作模板系统(例如 s/.../eval($repl)/e),或者在本应使用 eval BLOCK 时用于捕获异常。

如果有理由使用它,那就是执行生成的代码或用户提交的代码。生成代码是棘手且容易出错的,而且错误具有安全隐患。执行用户提交的代码是一个主要的安全问题。因此,每次使用 eval EXPR 都应仔细审查。

鉴于几乎每次使用都是具有重大安全隐患的错误,perlcritic 标记其用法是非常合适的。


在您的情况下,eval EXPR 的使用不是最佳选择。我会用

my $path = $module . ".pm";
$path =~ s{::}{/}g;
eval { require $path }

是的,这是便携式的。