タイトルは釣りです。
PHPの現場で公開されているPHPの例外 というPodcastを聞いていて、考えたこと。
お断り: 以下は個人の見解であって、所属先の見解ではありません。
聞けば聞くほど、「正しい例外の使い方」というのは難しいものだと思いました。
例外関連の話題となると例外とは何か? とか、例外の正しい使い方は? となるわけですが、大抵の場合は禅問答のような難しい話題になりがちです。
参考: 例外設計における大罪
「だから例外は難しい。」で思考停止にるのではなく、「間違った例外の使い方」を避けるようにしていけば地雷を踏むことはないはずです。
自分で投げた例外を自分自身でcatchしてはいけない。
関数・メソッド内で投げた例外を自分自身でcatchするなら、例外を投げる必要はありません。
例外は自分自身(関数・メソッド)以外の誰に向かって投げるものです。
それは例外を goto
の代わりに使っている証拠です。素直に goto
を使いましょう。
例外が必ずおきることを前提にしてはいけない。
例外は起きるかもしれないことを前提にした機構です。
必ず例外が起きることを前提としたコードは書いてはいけません。
try {
while(true){
// いつか例外をthrowする。はず…。
foo();
}
} catch (Exception $e) {
}
foo()
の中で例外が発生しないと、無限ループになります。
理由を明記せずに、例外を握りつぶしてはいけない。
発生した例外を catch
して、そのまま握りつぶすことがあります。
その理由が明記されていないと、その理由や、ただ単にコーディング漏れではないことを判断できません。
なぜその例外を握りつぶして良いかコメントに記述しましょう。
(以下、おまけ)PHP組み込みExceptionの分類案
Podcast内で話題になっていた、組み込みExceptionのLogicalException
とRuntimeExceptoin
という大分類の違いをどうとらえるかです。
私としては「実行時にだけ発生するようなエラー」で分類してしまったのが失敗の元だったと考えます。
http://php.net/manual/ja/class.runtimeexception.php
例外(コンパイルエラーも含む)は常に実行時にしか発生しえないので、この分類自体あまり意味があるとは思えません。
こんな感じの分類を提案したいところです。
上記に従い、例外は「例外は自分自身(関数・メソッド)以外の誰に向かって投げるもの」とすれば、関数(メソッド)の呼び出し関係が切り口になります。
- 呼び出し側に責任がある
- ランタイムが判断できる
- 存在しないメソッド(関数)を呼び出した場合
- 引数が足りない場合
- 引数の型エラー(Type Mismatch)の場合
- 0除算エラーの場合
- アンダーフロー・オーバフロー発生の場合
- 制御構造(
if
,for
,foreach
)への不正な引数。1
- ランタイムが判断できない
- 引数の値が(ビジネスロジックの観点で)不正の場合
- ランタイムが判断できる
- 呼び出された側に責任が無い
- 実装側に責任がある
- Assesionに引っかかった場合
- 実装側に責任が無い
- メモリ不足が発生した場合
- ファイルシステム関連のエラーが発生した場合
- I/O(ディスク、ネットワーク、DB、外部API)エラーが発生した場合
- シグナル割り込み発生の場合
- 実装側に責任がある
それでは良い例外ライフを。
-
ここでは、演算子は関数(メソッド)とみなしています。配列の参照
[]
も演算子とみなしています。 ↩