ずっと勘違いしていたことがありました。
PHPのタイプヒントは例外をスローしません。
マニュアルなりエラーメッセージなりをしっかり読めばわかる話ですが…
php.netより
タイプヒントの指定を満たさないとキャッチ可能な致命的エラーとなります。
エラーメッセージより
Catchable fatal error: Argument ...
ずっとcatchable
というワードに注目していたために勝手に 捕捉可能な例外をスローする だと思っていた。
実際は キャッチ可能な致命的エラー つまりfatal error
を発行するわけだったのです。
致命的なエラーをキャッチする
タイプヒントによって出力されるエラーにはCatchable fatal error ...
とくっついてくるのですが、
なんとなくこのメッセージだと、 ちゃんとエラーをキャッチして下さい と言われているようで気分がよくありません。
タイプヒントで発生するエラーレベルはE_RECOVERABLE_ERROR
です。
set_error_hundler
を利用してエラー発生の動作を制御してみます。
set_error_hundler(function($errorLevel, $errorMessage) {
switch($errorLevel) {
E_RECOVERABLE_ERROR:
echo $errorMessage;
exit(255);
break;
}
});
これで致命的なエラーをキャッチして処理を制御したことになるので出力されるエラーメッセージからCatchable fatal error:
の箇所が抜けて通常のエラーメッセージ形式の出力になります。
タイプヒントで例外をスローさせる
set_error_hundler
で例外をスローすれいいだけです、難しいことを考える必要はないですね。
set_error_hundler(function($errorLevel, $errorMessage) {
switch($errorLevel) {
E_RECOVERABLE_ERROR:
throw new InvalidArgmentException($errorMessage, $errorLevel);
break;
}
});
他のE_RECOVERABLE_ERRORと区別する
E_RECOVERABLE_ERROR
はタイプヒント以外でも発生する可能性があります。
タイプヒントのエラーであるかどうかはエラーメッセージをみて、そのエラーがタイプヒントのものであるかどうかを判定する必要があります。
define('TYPEHINT_PCRE', '/^Argument (\d)+ passed to (?:(\w+)::)?(\w+)\(\) must be an instance of (\w+), (\w+) given/');
set_error_hundler(function($errorLevel, $errorMessage) {
switch($errorLevel) {
E_RECOVERABLE_ERROR:
if (preg_match(TYPEHINT_PCRE, $errorMessage)) {
throw new InvalidArgmentException($errorMessage, $errorLevel);
} else {
throw new ErrorException($errorMessage, $errorLevel);
}
break;
}
});
まとめ
- phpには キャッチ可能な致命的エラー が存在する。
-
キャッチ可能な致命的エラー はエラーレベルが
E_RECOVERABLE_ERROR
になる。 -
E_RECOVERABLE_ERROR
はser_error_hundler
で処理を制御してあげないとエラーメッセージにCatchable fatal error ...
と出力される(つまりfatal errorになる) - タイプヒントで発生するエラーは
E_RECOVERABLE_ERROR