10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPのタイプヒントはキャッチ可能な例外をスローしない

Posted at

ずっと勘違いしていたことがありました。
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_ERRORser_error_hundlerで処理を制御してあげないとエラーメッセージにCatchable fatal error ...と出力される(つまりfatal errorになる)
  • タイプヒントで発生するエラーはE_RECOVERABLE_ERROR
10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?