🐡
例外の再スローは必要?不必要?(PHP)
概要
例外処理のcatch句でただ単にthrow
だけ書かれているの(再スロー)を見たことがあったので、それに意味があるのか考えてみました。
サンプルケース
サンプル1(呼び出し元関数側で例外をキャッチしない)
function throwException() {
throw new Exception("大変です!!");
}
function methodHoge() {
return throwException(); // ここで例外が発生
}
try {
methodHoge(); // この関数の内部で例外が発生
} catch (Exception $e) {
echo "エラーが発生しました: " . $e->getMessage(); // ここで例外をキャッチ
}
// 出力: エラーが発生しました: 大変です!!
サンプル2(呼び出し元関数側で例外をキャッチする)
function throwException() {
throw new Exception("大変です!!");
}
function methodHoge() {
try {
return throwException(); // ここで例外が発生
} catch (Exception $e) {
throw $e; // ここでキャッチして再スロー!!!!!!!
}
}
try {
methodHoge(); // この関数の内部で例外が発生
} catch (Exception $e) {
echo "エラーが発生しました: " . $e->getMessage(); // ここで例外をキャッチ
}
// 出力: エラーが発生しました: 大変です!!
結果としてはサンプル1もサンプル2も全く同じ結果になります。
サンプル2の再スローは必要なのか?
=>不必要
throw $e;
しかない場合は不要だと思います。
意味のないcatch句は書かない、本当に必要な箇所だけの精神です。
不要の理由として、下記2つだと考えています。
- 可読性が下がる
- どこもかしこもcatchして、ただ単に再スローばかりしていたらどの層もコードがcatch句ばかりになってしまいます。
- 大域脱出の良さを損なっている
- 大域脱出については下記で詳しく説明します
大域脱出とは
大域脱出とは、例外が発生したりthrowした場合、どんなに階層が深くても実行中の処理を中止し、呼び出し元ではなくその例外をtry-catchしているところまで処理を戻すことができます。
※ 普通の関数呼び出しでは、1つ手前の呼び出し元の関数に処理が戻ります。
この大域脱出があるおかげで、上位の層の意図した1箇所でcatch句を書いて例外のハンドリングがしやすくなっています。
さいごに
例外処理は奥が深いです。catch句の扱いには気を付けましょう。
参考
Discussion