2011-08-15 3 views
9

例外を処理する最良の方法は、Perlで連鎖するメソッドに投げられたものは何ですか?それを行うにはPerlのメソッドチェーンでエラーを処理するにはどうすればよいですか?

my $x = $obj->get_obj->get_other_obj->get_another_obj->do_something; 

何最善の方法:私はチェーンのいずれかの方法ならば0の値はundefを割り当てたい は例外

コードサンプルを投げますか? try/catch/finallyステートメントを毎回ラップする必要がありますか? 私が適用したい文脈は次のとおりです:私はCatalystとDBICを使用してWeb開発をしています。私は多くの連鎖結果セットを作成していますが、この結果セットのいくつかが例外をスローした場合、ただ0またはundefの値を割り当て、テンプレート(Template Toolkitを使用しているIm)のこのエラー。 try/catchですべての呼び出しをラップしないで別の方法がある場合は、私にお知らせください。同じコンテキスト(Catalyst/DBIC/TT)でこのタイプのエラーを処理するより良い方法が分かっている場合は、お勧めします。 実際の例は、ユーザーが何かを検索し、これが存在しない場合です。

答えて

8

これは、障害の発生時にnullオブジェクトを返すことでこれを処理します。そのオブジェクトは、単にそれ自身を返すことによってすべてのメソッドに応答するので、残りのメソッドを食べるまでそれを続けます。結局、$xを見て、それがあなたが期待した結果か、このヌルオブジェクトであるかどうかを見てください。

は、ここでそのようなことの例です:

use v5.12; 

package Null { 
    my $null = bless {}, __PACKAGE__; 
    sub AUTOLOAD { $null } 
    } 

すべての方法については、AUTOLOADインターセプトそれと呼ばれ、空のオブジェクトを返します。

エラーが発生すると、これらのNullオブジェクトのいずれかを返します。メソッドチェーンの途中ではまだオブジェクトが返ってくるので、次のメソッドを呼び出すとPerlは爆発しません。

sub get_other_obj { 
    ...; 
    return Null->new if $error; 
    ...; 
    } 

チェーンの最後に、戻ったものがNullオブジェクトかどうかを確認できます。それがあなたのものなら、何か悪いことが起きました。

これは基本的な考えです。 Nullクラスを改善して、メッセージとその作成場所を覚えておくか、またはいくつかの多態的メソッド(例えばsub is_success { 0 }など)を追加して、期待したオブジェクトのインターフェイスをうまく演奏させることができます。

私はこれについてどこか長いこと書いていたと思っていましたが、今は見つけられません。

+0

Setterメソッドは、nullを使用してcurを返すことを意味します賃貸価値たとえば、 '$ foo-> Name(" David ")は名前を' David'に設定し、 '$ foo-> Name'は現在の名前を返します。したがって、あるメソッドからのnull戻り値は、別のメソッドへの有効な入力である可能性があります。 –

+0

それは本当に問題ではありません。それはノーオペレーションです。後続の方法は何もしません。 nullオブジェクトを引数として渡すことはありません。それは指示対象です。前のメソッドがオブジェクトを返さない場合は、とにかくチェーンすることはできません。 –

+0

申し訳ありませんが私は理解しませんでした。 DBIC連鎖結果セットにどのように適用できますか? – nsbm

-1

overloadを使用するクラスを作成して、インスタンスオブジェクトが文字列/数値/ブール値コンテキストで評価されても、その値を返すことが考えられますが、依然としてメソッドを呼び出すことができます。 AUTOLOADメソッドは、常に$selfを返して、メソッドチェーンが同じエラーを伝播できるようにすることができます。

2

あなたはエラー処理方法のチェーンをラップするスカラー方法書くことができます。それを使用する

my $try = sub { 
    @_ > 1 or return bless {ok => $_[0]} => 'Try'; 

    my ($self, $method) = splice @_, 0, 2; 
    my $ret; 
    eval { 
     $ret = $self->$method(@_); 
    1} or return bless {error => [email protected]} => 'Try'; 
    bless {ok => $ret} => 'Try' 
}; 

{package Try; 
    use overload fallback => 1, '""' => sub {$_[0]{ok}}; 
    sub AUTOLOAD { 
     my ($method) = our $AUTOLOAD =~ /([^:]+)$/; 
     $_[0]{ok} ? $_[0]{ok}->$try($method, @_[1..$#_]) : $_[0] 
    } 
    sub DESTROY {} 
    sub error {$_[0]{error}} 
} 

を:

{package Obj; 
    sub new {bless [0]} 
    sub set {$_[0][0] = $_[1]; $_[0]} 
    sub add {$_[0][0] += ($_[1] || 1); $_[0]} 
    sub show {print "Obj: $_[0][0]\n"} 
    sub dies {die "an error occured"} 
} 

my $obj = Obj->new; 

say "ok 1" if $obj->$try(set => 5)->add->add->show; # prints "Obj 7" 
                # and "ok 1" 

say "ok 2" if $obj->$try('dies')->add->add->show; # prints nothing 

say $obj->$try('dies')->add->add->show->error; # prints "an error occured..." 

$try方法の最初の行は、次の構文を使用できます:

say "ok 3" if $obj->$try->set(5)->add->add->show; 
関連する問題