2017-05-19 3 views
2

Perlで関数のパラメータを検証する最もスマートな方法は何ですか?Perlで関数のパラメータを検証するにはどうすればよいですか?

コードスニペット

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


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

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

はperlで関数パラメータを検証したり、よりスマートな方法がありますする上記の方法は良い選択肢ですか? 多くの皆様に感謝します。これで

+1

関連[サブルーチン引数の検証にはどのようなPerlモジュールが便利ですか?】(https://stackoverflow.com/questions/1433070/what-perl-modules-are-useful-for-validating-subroutine-arguments)と[Perlサブルーチン引数](https://stackoverflow.com/questions/19234209/perl-subroutine-arguments)を参照してください。 –

+0

参照[オプションのサブルーチン引数のデフォルト値を指定する方法は?](http://stackoverflow.com/q/29577085/2173773)および[Perl:名前付きパラメータ検証のベストプラクティス](http://stackoverflow.com/q/19514694/2173773) –

答えて

10

これは、達成しようとしていること、ユーザー入力、ローカル機能、リモート機能のいずれかに大きく依存します。

私はいくつかのパラメータを意味しています。使用しようとすると「検証する」方が簡単です。たとえば、ファイル名を手作業ですべてトラップしようとするのではなく、単にopen .... or die $!に転送してください。

そして時には「デフォルトとオーバーライドする」方が賢明です。例えば:

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のプロトタイプが引数の種類をチェック(例えばスカラーですか、それは配列ですか?)値をチェックしないでください。には、配列を渡す際に予期しない影響があります。

私はあなたができるので、ハッシュに渡すと、デフォルト設定メカニズムに非常によく適していることをお勧めしたい:

#!/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の機能は他の多くの言語では表示されません。

具体的には、 'user supplied'が '汚染されている'と解釈するので、は妥当性検査なしでを使用できません。そして、それは

perlsec

を参照してくださいしかし、環境等をvarsの、安全でないパスが含まれています

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

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

は失敗します - systemは '汚染された' 許可されませんので、varsは。 (しかし、printの意)。 '汚れ'が削除される前に、検証手順(通常は正規表現など)に渡す必要があります。

+0

多くありがとうございます。あなたからの偉大で非常に有益な答え:) –

+2

あなたは 'die '値パラメタにダブルスの代わりにシングルクォートを使いたいかもしれません... match/^ \ w + $ /" '二重引用符で' $/'となります。 Perl変数として解釈されます。 – Dada

+0

良い点。改正された。 – Sobrique

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のより一般的なアドバイスに同意します。

+1

'||'の代わりに '/'を使って、あなたが概説している問題を解決することもできます。 (これは私がいくつかの場所にインストールされて見たより少し新しいバージョンのPerlを必要とします) – Sobrique

+0

@Sobriqueありがとう、そのことを忘れてしまった。 –

関連する問題