🐡

例外の再スローは必要?不必要?(PHP)

2024/02/07に公開

概要

例外処理の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句の扱いには気を付けましょう。

参考

https://stackoverflow.com/questions/5551668/what-are-the-best-practices-for-catching-and-re-throwing-exceptions
https://qiita.com/TairaNozawa/items/8788c4b20c60046ee80c

Discussion