LOG

PHPで例外処理

例外にはいろいろな種類がある。
デフォルトで定義されている例外は

Throwable // PHP7~ [interface]
 ├ Exception
 │ └ ErrorException
 └ Error                      // PHP7~
   ├ TypeError              // PHP7~
   ├ AssertionError         // PHP7~
   ├ ParseError             // PHP7~
   ├ ArithmeticError        // PHP7~
   │ └DivisionByZeroError // PHP7~

引用:定義済みの例外

ErrorはExceptionのサブクラスではないのでキャッチ出来ないので注意。

またSPLではExceptionを基底クラスとしたサブクラスが複数用意されている。

Exception
 ├ LogicException
 │ ├ BadFunctionCallException
 │ │ └ BadMethodCallException
 │ ├ DomainException
 │ ├ InvalidArgumentException
 │ ├ LengthException
 │ └ OutOfRangeException
 └ RuntimeException
   ├ OutOfBoundsException
   ├ OverflowException
   ├ RangeException
   ├ UnderflowException
   └ UnexpectedValueException

※ SPLは、標準的なインターフェイス、クラスを集めたものでPHP5~デフォルトでコンパイルされている。

今回は例外の種類ごとの使い分けやPHP7での変更点、は触れない。
例外の使い分けや、PHP7での変更点などは下記ページが分かりやすかった。


簡単な例外処理

例外処理をするには例外オブジェクトを必要であれば作成し、スローすることで処理する。
一番簡単な方法はtry/catch構文を使った方法。

try{
    throw new Exception("エラーメッセージ",1,null);
}catch(Exception $e){
    die($e->getMessage());
}

Exceptionの第3引数は$previousとなっており、スタックを積める。

try{
    $e1 = new Exception("エラー1",0,null);
    $e2 = new Exception("エラー2",0,$e1);
    $e3 = new Exception("エラー3",0,$e2);
    throw $e3;
}catch(Exception $e){
    echo '<pre>';
    dump($e);
    echo '</pre>';
}
// object(Exception)#4 (7) {
// ["message":protected]=>
// string(10) "エラー3"
// ...
// object(Exception)#4 (7) {
// ["message":protected]=>
// string(10) "エラー2"
// ...
// object(Exception)#4 (7) {
// ["message":protected]=>
// string(10) "エラー1"

これを利用しException::getPrevious()メソッドを使い例外を配列に格納する。

$err_arr = [];
try{
    $e1 = new Exception("エラー1",0,null);
    $e2 = new Exception("エラー2",0,$e1);
    $e3 = new Exception("エラー3",0,$e2);
    throw $e3;
}catch(Exception $e){
    do{
        $err_arr[] = $e->getMessage();
    }while($e = $e->getPrevious());

    $err_arr = array_reverse($err_arr);
    echo '<pre>';
    var_dump($err_arr);
    echo '</pre>';
}

// array(3) {
// [0]=>
// string(10) "エラー1"
// [1]=>
// string(10) "エラー2"
// [2]=>
// string(10) "エラー3"

例外処理、エラー処理のハンドラを定義する

例外処理、エラー処理のハンドラ関数を設定するのに
set_exception_handler()set_error_handler()が使える。

set_exception_handler()

  • 例外処理
  • try/catch構文でキャッチ出来なかった例外の処理が出来る。
  • 元のハンドラ関数に戻したい場合はrestore_exception_handler()を使う。
throw new Exception("error");
// Fatal error: Uncaught exception 'Exception' with message 'error' in xxx/xxxx/xxx.php:xx....

という具合にFatal errorになる。
set_exception_handler()で定義してやると。

set_exception_handler(function (Exception $e) {
    var_dump("exception handler");
});
throw new Exception("error");
// exception handler

set_error_handler()

  • エラー処理
  • error_reporting()でエラー出力を設定していてもset_error_handler()が対応している全てのエラーでハンドラ関数が呼ばれるのでエラータイプによって処理を分けたい場合、error_reporting()の型を読み、適宜処理する必要がある。
  • ハンドラ関数がfalseを返さない限り、第2引数で指定した型のエラーで標準のハンドラが呼ばれない。
  • 元のハンドラ関数に戻したい場合はrestore_error_handler()を使う。
1 / 0;
// Warning: Division by zero in...

デフォルトのハンドラが呼ばれる。
エラーハンドラを定義すると

set_error_handler(function(){
    var_dump("error handler");
});
1 / 0;
// error handler

ハンドラ関数がfalseを返すとその後にデフォルトのハンドラ関数が呼ばれる。

この2つのメソッドで拾えないエラーはスクリプト終了時に実行する処理を登録できるregister_shutdown_function()を使うと良い。

また、PHP7からはエラーも例外をスローするように変更されたそう。
ただし全てのエラーがスローされるわけではない。


エラーをスローさせる。

set_error_handler(function(){
    throw new Exception('Error Exception');
});