#1 に反対することをお勧めします。これは、記述されないエラー処理コードが増えるためです。たとえば、false を返すだけの場合、これは正常に機能します。
my $obj = Class->new or die "Construction failed...";
しかし、無効なオブジェクトを返すと...
my $obj = Class->new;
die "Construction failed @{[ $obj->error_message ]}" if $obj->is_valid;
また、エラー処理コードの量が増えると、それが書き込まれる確率が低下します。そして、それは直線的ではありません。エラー処理システムの複雑さを増すことで、実際の使用でキャッチされるエラーの量を実際に減らすことができます。
また、任意のメソッドが呼び出されたときに問題の無効なオブジェクトが死ぬことにも注意する必要があります (is_valid
および を除くerror_message
)。これにより、さらに多くのコードと間違いの可能性が生じます。
しかし、失敗に関する情報を取得できることには価値があることに同意します。これにより、 false ( でreturn
はないreturn undef
) を返すことが劣ります。伝統的に、これは DBI のようにクラス メソッドまたはグローバル変数を呼び出すことによって行われます。
my $dbh = DBI->connect($data_source, $username, $password) or die $DBI::errstr;
しかし、A) エラー処理コードを書く必要があり、B) 最後の操作に対してのみ有効であるという問題があります。
一般に、最善の方法は、例外をスローすることcroak
です。通常、ユーザーは特別なコードを記述しません。エラーは問題の時点で発生し、デフォルトで適切なエラー メッセージが表示されます。
my $obj = Class->new;
ライブラリ コードで例外をスローすることに対する Perl の従来の推奨事項は、失礼であるとして古くなっています。Perl プログラマーは (ついに) 例外を受け入れています。エラー処理コードを何度も何度も書くのではなく、ひどく忘れがちな例外 DWIM を使用します。確信が持てない場合は、autodieを使い始めてください( pjf のビデオをご覧ください)。二度と戻ることはありません。
例外は、ハフマン エンコーディングを実際の使用に合わせます。コンストラクターが機能することを期待し、機能しない場合はエラーが必要になるという一般的なケースは、最小のコードになりました。そのエラーを処理したいというまれなケースでは、特別なコードを書く必要があります。そして、特別なコードはかなり小さいです。
my $obj = eval { Class->new } or do { something else };
すべての呼び出しを でラップしていることに気付いたeval
場合、それは間違っています。例外は例外的であるため、そう呼ばれます。上記のコメントのように、ユーザーのために適切なエラー処理が必要な場合は、エラーがスタックにバブルアップするという事実を利用してください。たとえば、適切なユーザー エラー ページを提供し、エラーをログに記録する場合は、次のようにします。
eval {
run_the_main_web_code();
} or do {
log_the_error($@);
print_the_pretty_error_page;
};
どこにでも散在するのではなく、コール スタックの一番上に 1 か所だけ必要です。たとえば、これをより小さな増分で利用できます...
my $users = eval { Users->search({ name => $name }) } or do {
...handle an error while finding a user...
};
2 つのことが起こっています。1)Users->search
常に真の値を返します。この場合は配列参照です。それは簡単なmy $obj = eval { Class->method } or do
仕事をします。それはオプションです。しかし、もっと重要なことは、2) 特別なエラー処理をUsers->search
. 内部Users->search
で呼び出されるすべてのメソッドとそれらが呼び出すすべてのメソッド...それらは例外をスローするだけです。そして、それらはすべてある時点で捕捉され、同じように処理されます。例外を気にするポイントで例外を処理すると、はるかにきちんとした、コンパクトで柔軟なエラー処理コードが作成されます。
croak
文字列だけではなく、文字列のオーバーロードされたオブジェクトを ing することで、より多くの情報を例外に詰め込むことができます。
my $obj = eval { Class->new }
or die "Construction failed: $@ and there were @{[ $@->num_frobnitz ]} frobnitzes";
例外:
- 発信者が何も考えずに正しいことを行う
- 最も一般的なケースでは最小限のコードしか必要としない
- 発信者に障害に関する最大限の柔軟性と情報を提供する
Try::Tinyなどのモジュールeval
は、例外ハンドラーとしての使用に関するハングの問題のほとんどを修正します。
非常に高価なオブジェクトを持っていて、それを部分的にビルドして続行したいというユースケースについては...私にはYAGNIの匂いがします。本当に必要ですか?または、処理が早すぎる肥大化したオブジェクト設計があります。必要な場合は、構築を続行するために必要な情報を例外オブジェクトに入れることができます。