2014-02-23 3 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

: 당신이 해시에 대한 참조가 있는지 확인하는

defined($x) && eval { @$x; 1 } 

적절한 방법 : 당신이 배열에 대한 참조가있는 경우


적절한 방법 확인 한 가지 방법 이상의 것입니다. 모든 접근 방식에는 장단점이 있습니다. 일부 접근법은 다른 것보다 관용적/읽기 쉽고 간결하며 유지 보수가 가능합니다. 나는 다음 질문이이 질문에 더 적합한 제목이라고 생각한다 : 서브 루틴 주장을 확인하는 가장 관용적 인 방법은 무엇인가? – 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)를 사용하는 방법이 있습니다. [여기에 Params 대신 Type :: Params를 사용하는 것이 좋습니다. Validate] (https://metacpan.org/source/TOBYINK/Type-Tiny-0.038/examples/benchmark-param-validation.pl#L122). – tobyink

1

없음 당신은 내가 중요하다고 생각 실패에 대한 이유를 제공하는 디스플레이에게 어떤 메시지를 표시하지 않습니다.

또한 라이브러리 서브 루틴 내에서 die 대신 croak을 사용하는 것이 좋으므로 호출자의 관점에서 오류가보고됩니다.

나는 모든 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 
} 
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 }