PHPDocには @throws
という表記でそのメソッドが投げ得る例外を文書化することができます。
今回はその個人的使い方の方針をまとめます。2021年バージョンです。
※ 一度社内に展開してガラッと見解が変わったのでそれを反映させてます
そもそも、PHPDocの @throws とは
- @throwsタグは、メソッドが特定のエラー/例外を投げる可能性があることを示すために使用できます
/** * データベースに接続する * * @param string $dsn 接続情報 * @return bool 接続可否 * @throws RecoverbleDbException 接続に一時的に失敗した場合にthrowされる */ function connect($dsn) { // something... }
https://zonuexe.github.io/phpDocumentor2-ja/references/phpdoc/tags/throws.html
PhpStormで @throws はどのように扱われるか
PhpStorm 2017.3
- 新しい例外解析エンジンを搭載し、処理されない例外を見つけたり、書き漏れている @throws タグを見つけたりなど出来るようになった
PhpStorm 2018.1
- 解析対象から外すべき例外のリストを設定できるようになった
- Preferences -> Languages & Frameworks -> PHP -> Analysis -> Unchecked Exceptions
- 初期値では以下の3つを除外している. 継承先の例外も除外される点に注意*1
\RuntimeException
\Error
\LogicException
エラー表示
PhpStorm は、呼び出したメソッドの PHPDoc の @throws をヒントに、try-catch の不足などをインスペクションすることができます。
例: @throwsに記載されている例外のハンドリングが不足していたケース
例2: メソッドの内部でthrowされている例外が@throwsに書かれていないケース (除外設定されている場合は警告は出ない)
@throws に関する問題点 in PhpStorm
テストでReflectionClassなどを使うと黄色い警告が出てしまう
- テストケースの中でReflectionクラスを使うことはPHPだと比較的よくある
- このときに
ReflectionException
(\Exceptionの派生クラス)のtry-catchが不足していると警告が出てしまう - しかしここで例外が来ることを想定して捕捉する必要性は薄い
- 捕捉してできることもほぼないし、実装ミスでなければ生じ得ない
- なので @noinspection を使うことで許容
/** @noinspection PhpUnhandledExceptionInspection */ $clientProp = new ReflectionProperty($this->logger, 'client');
外部ライブラリなどを使ったときに黄色い警告が出てしまう
- 非検査例外のつもりで、\Exceptionを継承したユーザー独自例外を投げてきたりするライブラリがある
- ユーザー独自例外は捕捉必須であるとPhpStormに怒られるが、非検査例外なので捕捉しても意味がない
- これは現状のPHPコミュニティにおいて例外の意味するところに宗派があるのが原因の1つ
- PHPの例外はすべて非検査例外 v.s. RuntimeException以外は検査例外など
- 仕方ないと割り切るか、別の設計のライブラリを使う
\Error や \Throwableなどを使うと黄色い警告が出てしまう
- 基本的にこれら2つを直接アプリケーションから使用するのは避けるべき (理由)
- しかし、「どんな例外が起きても必ず後始末として実行したい処理」などのために
catch(\Throwable $t) { ...後処理; throw $t; }
とすると、PhpStormが@throwsを書け! と警告を出してしまう - これも仕方ないと思って許容
- このために @noinspection をしはじめると際限がなかったり、 \Error や \Throwable を除外例外の設定に入れてしまうとその派生クラスまでインスペクションが動かなくなるのでできれば避ける
結論:@throwsの使い方 2021年ver.
@throws
は仕様・ドキュメントであって、実装を強制するものではないスタンス- 「
@throws
に書いてあるものは必ず呼び出し元がtry-catchなどでハンドリングしろ!」とはしない - 「
@thorws
に必ず書くのはこれ!書いちゃいけないのはこれ!」みたいに強いルールは決めない
- 「
- 基本的には起こりうる例外を列挙していく
- ただし仕様としてあまり意味をなさないものは書かなくても良い(メソッド内の更に内部の深いところで発生する例外など)
- 仕様を表現するときに、以下のようなケースでは書いておいたほうがいいので
@throws
に記載することを推奨- 呼び出し側で必ず捕捉してほしい例外
- 知っておいてほしい仕様を表現するもの(非検査例外や捕捉しても意味が薄いものであっても)
- 非検査例外
- PHP7におけるError
- TypeError, ParseError, AssertionError, DivisionByZeroErrorなど
- LogicException
- BadFunctionCallException, InvalidArgumentException, OutOfRangeExceptionなど
- PHP7におけるError
- 捕捉しても意味が薄いもの
- \Exception, \Throwable
- 非検査例外
*1:例えばHttpExceptionなどCakePHPの独自例外は全てRuntimeExceptionを継承しているので、初期状態でこれらは @throws のインスペクションが実行されない