例外をどのような状況に投げるかもしくは投げないか、というのはわりと意見が分かれるところです。もちろん、プログラミング言語によっても異なりますが、同じプログラミング言語ユーザ同士でも様々です。
基本の考え方
ベースとしては、Effective Java の項目 39 にある下記の方針が参考になります。
例外的な状況の時にのみ例外を使う。
Effective Java
禅問答のような定義ですが、これには異論は無いでしょう。例外を正常フローで利用したり、制御構造に用いるべきではありません。
人によって異なるのは「例外的な状況」の解釈です。
例外的な状況
この「例外的な状況」の解釈は人によって異なるようで、これまでも議論になっていました。これまで聞いた解釈を乱暴に分けると以下の 2 パターンに分かれます。
1. アプリケーションから独自の例外を投げる派
ランタイムやミドルウェア連携などプラットフォーム起因のエラーだけではなく、 アプリケーションやドメインにおけるエラーを例外としてスローする派です。例外クラスも必要に応じて定義します。
例外をエラー処理に積極的に利用する考え方ともいえ、例えば、入力値におけるバリデーションエラーやドメインロジックのエラーにおいても例外を利用します。
2. プラットフォームやフレームワークが投げる例外以外は使わない派
ランタイムやミドルウェア連携などプラットフォーム起因のエラーなど深刻なエラーでのみ例外を利用し、アプリケーションにおけるエラーにおいては例外を利用しない考え方です。
この考え方の人の中には、例外クラスはアプリケーション独自で定義せず、アプリケーションからは例外をスローしない(ランタイムやフレームワーク、ライブラリからの例外のみ扱う)という意見もありました。
アプリケーションのエラーは、戻り値で通知することになります。(特殊な値(null や false)を使ったり、原因別に戻り値を返すなど)
アプリケーションから独自の例外を投げる派の意見
私は、前者の「例外を積極的に使う派」です。理由としては、下記のようなメリットを感じています。 (なお、ここでは PHP を対象として、検査例外のことは考えていません。)
- [実装][利用] エラー処理を例外に統一できる。
- [利用] 呼び出す側は例外だけ対応すれば良い。(catch する / 対応しない(上位にスロー))
- [利用] どのレイヤでエラー処理するかを呼び出し側が選べる。(上位レイヤに伝播できるので、フレームワークの統一的なエラー処理に任せてしまうなどが簡単)
- [実装] エラー時は例外を投げれば良いので、ガード節の代わりにもなる。
- [実装] テストでは、@expectedException でテストを書けば良いので、何のテストか分かりやすい。(正常時は例外飛ばないので)
- [利用] try / catch を書けば、try の中は正常系、catch の中は異常系と処理が分かれて分かりやすい。
- [利用] 戻り値のエラー判定が不要。例外が飛ばなければ正常終了と判断できる。
- [利用] 例外クラスが持つ情報量が多い。(特にスタックトレース)
さいごに
例外については、人それぞれ思いがあるようで、議論になりやすいところです。この機会に色々な人の意見を聞いてみたいですね。
今日開催の関西 PHP 勉強会でも、話しましょう。
https://kphpug.doorkeeper.jp/events/55554
EFFECTIVE JAVA 第2版 (The Java Series)
- 作者: Joshua Bloch,柴田芳樹
- 出版社/メーカー: 丸善出版
- 発売日: 2014/03/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (10件) を見る
追記
Twitter へ頂いたコメントをまとめました。色々な意見がありますね。
はてぶでも多くのコメントがあったので、こちらも追記。