在perl中进行防御性编程的最佳(或推荐)方法是什么? 例如,如果我有一个必须用(定义的)SCALAR,ARRAYREF和一个可选的HASHREF调用的子。
我见过的三种方法:
sub test1 {
die if !(@_ == 2 || @_ == 3);
my ($scalar, $arrayref, $hashref) = @_;
die if !defined($scalar) || ref($scalar);
die if ref($arrayref) ne 'ARRAY';
die if defined($hashref) && ref($hashref) ne 'HASH';
#do s.th with scalar, arrayref and hashref
}
sub test2 {
Carp::assert(@_ == 2 || @_ == 3) if DEBUG;
my ($scalar, $arrayref, $hashref) = @_;
if(DEBUG) {
Carp::assert defined($scalar) && !ref($scalar);
Carp::assert ref($arrayref) eq 'ARRAY';
Carp::assert !defined($hashref) || ref($hashref) eq 'HASH';
}
#do s.th with scalar, arrayref and hashref
}
sub test3 {
my ($scalar, $arrayref, $hashref) = @_;
(@_ == 2 || @_ == 3 && defined($scalar) && !ref($scalar) && ref($arrayref) eq 'ARRAY' && (!defined($hashref) || ref($hashref) eq 'HASH'))
or Carp::croak 'usage: test3(SCALAR, ARRAYREF, [HASHREF])';
#do s.th with scalar, arrayref and hashref
}
答案 0 :(得分:3)
我不会使用它们中的任何一个。除了不接受许多数组和哈希引用之外,您使用的检查几乎总是多余的。
>perl -we"use strict; sub { my ($x) = @_; my $y = $x->[0] }->( 'abc' )"
Can't use string ("abc") as an ARRAY ref nda"strict refs" in use at -e line 1.
>perl -we"use strict; sub { my ($x) = @_; my $y = $x->[0] }->( {} )"
Not an ARRAY reference at -e line 1.
检查的唯一好处是您可以使用croak
在错误消息中显示调用者。
检查您是否有对数组的引用的正确方法:
defined($x) && eval { @$x; 1 }
检查您是否有对哈希的引用的正确方法:
defined($x) && eval { %$x; 1 }
答案 1 :(得分:3)
use Params::Validate qw(:all);
sub Yada {
my (...)=validate_pos(@_,{ type=>SCALAR },{ type=>ARRAYREF },{ type=>HASHREF,optional=>1 });
...
}
答案 2 :(得分:1)
您显示的所有选项都不会显示任何消息,以便为失败提供原因,我认为这是至关重要的。
最好在库子例程中使用croak
而不是die
,以便从调用者的角度报告错误。
我会将所有if !
替换为unless
。前者是C程序员的习惯。
我建议这样的事情
sub test1 {
croak "Incorrect number of parameters" unless @_ == 2 or @_ == 3;
my ($scalar, $arrayref, $hashref) = @_;
croak "Invalid first parameter" unless $scalar and not ref $scalar;
croak "Invalid second parameter" unless $arrayref eq 'ARRAY';
croak "Invalid third parameter" if defined $hashref and ref $hashref ne 'HASH';
# do s.th with scalar, arrayref and hashref
}