如何验证 Perl 中的函数参数?

How can I validate function parameters in Perl?

能否请您告诉我在 Perl 中什么是验证函数参数最聪明的方法?

代码片段:

sub testfunction {
    my ($args) = @_;
    my $value = $args->{value} || die "no value set";
    # process value ...
}


testfunction({value => 'Hallo'});

testfunction({novalue => 'Hallo'});

以上方法是在 perl 中验证函数参数的一个很好的替代方法还是有更聪明的方法? 非常感谢大家。

这个问题:

$args->{value} || die "no value set";

是否定义了值但设置为零时会失败。

testfunction({value => 0});  #Oops!

如果值不允许为零,那可能没问题。但一般来说,更好的设计是使用 exists// 检查哈希键是否已定义。

die "Value not defined!" if not exists $args->{value};

die "Value not defined!" unless exists $args->{value};

$args->{value} // die "Value not defined!";

对于这个简单的语句,我倾向于选择 exists,因为我认为它读起来更清楚一些。但是 // 允许一些不错的事情,比如替换默认值,如 Sobrique 的回答所示。我也同意 Sobrique 关于方法的更一般性建议。

这在很大程度上取决于您要完成的任务,以及它是用户输入、本地函数还是远程函数。

我的意思是,一些参数 - 'validate' 尝试使用它要容易得多。例如一个文件名 - 与其尝试手动捕获所有边缘情况,不如将其传递给 open .... or die $!

有时 - 'default-and-override' 更明智。例如:

my ( $first_thing, $second_thing ) = @_; 
$first_thing //= "default value";
$second_thing //= 0; 

注意 - 使用 // 而不是 || - 它在用法上 相似 ,但它只是测试未定义 - 而不是被定义 - but-false,例如 ''0

有时您希望通过应用一组验证正则表达式进行更好的验证。请注意,有些东西(例如电子邮件地址或 IP 地址)可能比您想象的要复杂得多,无法彻底验证 - 因此 'was there a parameter at all' 的简单边缘情况可以工作。

当然,到时候你也可以开始看function prototypes。这与您可能从其他语言中想到的原型制作完全不同:

#!/usr/bin/env perl

#says - must have a single scalar arg. 
sub testfunction($) {
   my ( $required_arg ) = @_; 
   print $required_arg;
}

testfunction(1);
testfunction;

后者将失败:

Not enough arguments for main::testfunction

注意 - perl 原型检查参数的 typenumber(例如,它是标量还是数组)。但是不要检查值,并且 can 在传入数组时会产生一些稍微出乎意料的效果。

我建议传递哈希值非常适合默认机制,因为您可以:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;

my %defaults = (
  "test" => 1,
);

sub with_default {
    my %args = (%defaults, @_); 
    print Dumper \%args; 
}

with_default;
with_default(test => 4 );

但是回到你原来的情况 - 如果你的函数在没有设置 'value' 的情况下根本无法工作,那么最好在代码中拼写出来:

if ( not defined $args -> {value} 
  or not $args -> {value} =~ m/^\w+$/ ) {
   die 'value parameter must be supplied and match m/^\w+$/';
}

此时可能值得一提的是 'taint' 模式。这是 perl 的一项功能,您在许多其他语言中都看不到。

它明确告诉解释器 'user supplied' 是 'tainted',因此 不能 未经验证就使用。这包括不安全的路径、环境变量等。

perlsec

但是:

#!/usr/bin/env perl -T
use strict;
use warnings;

system "echo $ENV{'USERNAME'}";

将失败 - 因为 system 不允许 'tainted' 变量。 (但是 print 会)。在删除 'taint' 之前,您需要通过验证步骤(例如,通常是正则表达式)来传递它。