2014-02-23 53 views
2

什麼是在perl中進行防禦性編程的最佳(或推薦)方法? 例如,如果我有必須調用一個(定義)SCALAR,一個ARRAYREF和一個可選的HASHREF的子。perl防禦性編程(die,assert,croak)

我見過的方法三:

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

有不僅僅是一種方式去做。所有的方法都有其優點和缺點。一些方法比其他方法更習慣/可讀/簡潔/可維護。我認爲以下是對這個問題更合適的標題:檢查子程序參數最常用的方法是什麼? – Zaid

+3

您是否考慮過CPAN產品? ['Params :: Validate'](https://metacpan.org/pod/Params::Validate)和['Type :: Params'](https://metacpan.org/pod/Type::Params)look像很好的候選人。 – Zaid

回答

3
use Params::Validate qw(:all); 

sub Yada { 
    my (...)=validate_pos(@_,{ type=>SCALAR },{ type=>ARRAYREF },{ type=>HASHREF,optional=>1 }); 
    ... 
} 
+0

FWIW,[這裏是你如何使用Type :: Params](https://gist.github.com/tobyink/9177725)和[這是爲什麼你可能想使用Type :: Params而不是Params ::驗證](https://metacpan.org/source/TOBYINK/Type-Tiny-0.038/examples/benchmark-param-validation.pl#L122)。 – tobyink

1

的選項都不告訴你顯示器的任何消息給失敗,我認爲這是最重要的一個原因

在庫子程序內優選使用croak而不是die,以便從調用者的角度報告錯誤。

我會用unless替換所有出現的if !。前者是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 
} 
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 }