请告诉我Perl中哪些是验证函数参数的最明智的方法?
代码段:
sub testfunction {
my ($args) = @_;
my $value = $args->{value} || die "no value set";
# process value ...
}
testfunction({value => 'Hallo'});
testfunction({novalue => 'Hallo'});
以上方式是验证perl中的函数参数的好方法还是有更聪明的方法? 非常感谢大家。
答案 0 :(得分:10)
这很大程度上取决于您尝试完成的内容,以及它的用户输入,本地功能还是远程功能。
我的意思是,一些参数 - 它更容易验证'通过尝试使用它。例如文件名 - 而不是试图手动捕获所有边缘情况,只需将其传递给open .... or die $!
有时候 - 默认 - 覆盖'更明智。 E.g:
my ( $first_thing, $second_thing ) = @_;
$first_thing //= "default value";
$second_thing //= 0;
注意 - 在使用中使用//
而不是||
- 它的类似的,但它只测试未定义 - 而不是被定义 - 但是 - 例如''
或0
。
有时您希望通过应用一组验证正则表达式来更好地进行验证。只是要小心,有些东西 - 比如电子邮件地址或IP地址 - 可能比你想象的要彻底验证要复杂得多 - 所以一个简单的边缘情况是'是否有参数?可以工作。
当然,此时您也可以开始查看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原型检查参数的类型和 number (例如它是标量,是数组)。但是,不要检查值,并且可以在传入数组时有一些意想不到的效果。
我建议传入哈希非常适合默认机制,因为你可以:
#!/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 );
但是要回到原来的情况 - 如果你的功能只是在没有“价值”的情况下工作了。如果设置好了,那么在代码中拼出它是件好事:
if ( not defined $args -> {value}
or not $args -> {value} =~ m/^\w+$/ ) {
die 'value parameter must be supplied and match m/^\w+$/';
}
可能值得一提的是'污染'此时的模式。它是您在许多其他语言中看不到的perl
的功能。
它具体告诉口译员“用户提供了”'被污染的'因此不能在没有验证的情况下使用。这包括不安全的路径,环境变量等。
请参阅perlsec
可是:
#!/usr/bin/env perl -T
use strict;
use warnings;
system "echo $ENV{'USERNAME'}";
会失败 - 因为system
不会允许' tainted'瓦尔。 (但print
会)。您需要在“污点”之前通过验证步骤(例如正则表达式)。已移除。
答案 1 :(得分:3)
这个问题:
$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关于方法的更一般的建议。