例外:これは良い習慣ですか?
-
01-07-2019 - |
質問
これは PHP で書かれていますが、実際には言語に依存しません。
try
{
try
{
$issue = new DM_Issue($core->db->escape_string($_GET['issue']));
}
catch(DM_Exception $e)
{
throw new Error_Page($tpl, ERR_NOT_FOUND, $e->getMessage());
}
}
catch(Error_Page $e)
{
die($e);
}
ネストされた try、catch ブロックは従うべき良い習慣ですか?エラー ページだけだと少し大きそうですが、エラーが発生すると Issue Datamanager が例外をスローするので、これがエラー検出の良い方法だと考えています。
Error_Page 例外は単なるエラー ページ コンパイラです。
私は単なる衒学的かもしれませんが、これはエラーを報告する良い方法だと思いますか?そうであれば、これを書くより良い方法を提案していただけますか?
ありがとう
解決
ページのロジックに例外を使用していますが、個人的にはそれは良いことではないと思います。例外は、エラー ページの出力を制御するためではなく、問題や予期せぬ事態が発生したことを知らせるために使用する必要があります。例外に基づいてエラー ページを生成したい場合は、次の使用を検討してください。 set_Exception_handler. 。キャッチされなかった例外は、指定したコールバック メソッドを通じて実行されます。これは例外の「致命的」性を阻止するものではないことに注意してください。例外がコールバックを介して渡された後、捕捉されなかった例外が発生すると、実行は通常どおり停止します。
他のヒント
巣は作らないほうがいいと思います。複数の例外タイプが予想される場合は、複数のキャッチを用意します。
try{
Something();
}
catch( SpecificException se )
{blah();}
catch( AnotherException ae )
{blah();}
理想は、例外を処理できるレベルで例外をキャッチすることです。前ではありません (時間の無駄)、後ではありません (文脈が失われます)。
したがって、たとえば DM_Issue を作成する場所が他にもあり、ERR_SOMETHING_ELSE が必要な場合や、$tpl の値が異なる場合など、$tpl と ERR_NOT_FOUND が新しい DM_Issue 呼び出しに近い「既知」の情報である場合、次のようにします。最初の例外を正しい場所でキャッチしています。
そこからどうやって死に至るかは別の問題だ。代替案は、その場で死ぬことだろう。しかし、それを行うと、エラーの後、終了する前に、介在するコードが何かを行う機会 (何らかの方法で何かを解決したり、エラー ページを変更したりするなど) ができなくなります。明示的な制御フローがあるのも良いことです。だから、あなたは大丈夫だと思います。
あなたの例は完全なアプリケーションではないと仮定しています。そうであれば、おそらく不必要に冗長であり、DM_Exception catch 句で死ぬ可能性があります。しかし、実際のアプリについては、何もない場所でただ死ぬわけではないという原則を私は認めます。
ニーズによってはこれで問題ないかもしれませんが、ラッピングで元の例外からのスタック トレース (および場合によってはその他の) 情報が失われるため、例外をキャッチし、メッセージを新しい例外でラップして、それを再スローすることは一般的にかなりためらわれます。例外。もしあなたが〜なら もちろん ラッピング例外を調べるときにその情報が必要ない場合は、おそらく問題ありません。
PHPについてはよくわかりませんが、例えばC# では複数の catch-Block を使用できるため、try/catch の組み合わせをネストする必要はありません。
一般に、try/catch/finally によるエラー処理は、エラー ページ「のみ」を表示する場合も含めて、常に常識であると私は信じています。これは、エラーを処理し、クラッシュ時の奇妙な動作を回避するためのクリーンな方法です。
問題が見つからない場合でも例外はスローしません。これはアプリケーションの有効な状態であり、404 を表示するためだけにスタック トレースは必要ありません。
捕捉する必要があるのは、SQL エラーなどの予期しないエラーです。そのような場合に例外処理が役に立ちます。コードを次のように変更します。
try {
$issue = DM_Issue::fetch($core->db->escape_string($_GET['issue']));
}
catch (SQLException $e) {
log_error('SQL Error: DM_Issue::fetch()', $e->get_message());
}
catch (Exception $e) {
log_error('Exception: DM_Issue::fetch()', $e->get_message());
}
if(!$issue) {
display_error_page($tpl, ERR_NOT_FOUND);
}
else
{
// ... do stuff with $issue object.
}
例外は、データベース クエリが適切に実行されない、または構成が間違っているなど、サイトを破壊する可能性のあるイベントがある場合にのみ使用してください。良い例としては、Apache プロセスがキャッシュまたはログ ディレクトリに書き込みできないことが挙げられます。
ここでの考え方は、例外は、サイト全体を破壊する可能性のあるコードを開発者が停止して、展開前に修正できるようにするためのものであるということです。これらは、環境が変化したかどうかを確認するための健全性チェックでもあります (つまり、誰かがキャッシュ フォルダーのアクセス許可を変更したり、データベース スキームを変更したりした場合、サイトは何かに損害を与える前に停止されます。
だから、いいえ。ネストされた catch ハンドラーは良いアイデアではありません。私のページでは、index.php ファイルがコードを try...cache ブロックでラップしており、何か問題が発生した場合は、本番環境かどうかを確認します。そして私に電子メールを送って一般的なエラーページを表示するか、画面上にエラーを直接表示します。
覚えて:PHPはC#ではありません。C# は (ASP.net の例外 (へー、冗談じゃない :p) を除いて) 状態を含むアプリケーション向けですが、PHP はステートレスなスクリプト言語です。