【PHP】エラー及び例外ハンドラーの定義

PHPのエラー及び例外を検知するハンドラー

PHPプログラムで発生するエラー及び例外を確実に検知し処理するためのハンドラーの定義方法についてメモします。

エラー及び例外発生時はユーザへエラー画面やメッセージを表示し、開発者にはログ出力やその他の方法で発生したエラーを通知させるのが一般的です。

エラーレベルの種類や設定については以下の記事を参照ください。

【PHP】🔰エラーレベルの種類と画面出力設定

環境: PHP 5.3.29, PHP 7.4.15, PHP 8.0.21

【エラーの検知】set_error_handler

PHPのエラーはその種類がFatal error(致命的なエラー)でない場合、処理がそのまま継続できるため、エラーが発生していた場合でも気が付きにくいという問題があります。

set_error_handler関数を使用することにより、Warning, NoticeなどFatal error以外のエラーを検知し、適切な処理を行うことができます。

set_error_handler(
    function ($errno, $errstr, $errfile, $errline) {
        // エラーに対する処理
    }
);

set_error_handlerという関数名で予約されていますが、引数にユーザ定義のコールバック関数を指定します。

コールバック関数はset_error_handlerの外側に定義することもでき、その場合は文字列として関数名を引数に指定します。

set_error_handler('handler');

function handler($errno, $errstr, $errfile, $errline) {
    // エラーに対する処理
}

エラーを例外に変換

set_error_handlerを利用して、発生したエラーを例外に変換することで通常の例外処理のように適切な対処を行うことができます。

(エラー発生時にPHPに用意されているエラー例外、ErrorExceptionを投げます)

set_error_handler(
    function ($errno, $errstr, $errfile, $errline) {
        throw new ErrorException('エラーの原因: ' . $errstr, 0, $errno, $errfile, $errline);
    }
);

注意
set_error_handlerを登録するよりも前に発生したエラーは検知できないため、実行プログラムのなるべく先頭に近い場所で登録しておく必要があります。

また、コールバックの引数がPHP 8系から新しい仕様へ変更されている点に注意が必要です。

PHP 8系〜 set_error_handler関数の引数

【未catch例外を処理】set_exception_handler

try〜catch構文によって補足されなかった例外はset_exception_handler関数を登録しておくことで処理することができます。

set_exception_handler(
    function ($exception) {

        echo $exception->getMessage();
    }
);

set_error_handlerと同様コールバックのユーザ定義関数を指定し、catchできなかった例外を処理します。
(実行プログラムの起点をtry〜catchで囲むのと同様の対処)

前述のset_error_handlerでErrorExceptionに変換したエラーもこのset_exception_handlerで処理できるようになります。

(PHP 7〜) Fatal Errorの捕捉

PHPはバージョン7系から大半のエラーがErrorクラスの例外に変換されてスローされる仕様になっているため、set_error_handlerで捕捉されないFatal Errorのエラーがset_exception_handlerで捕捉できるようになっています。

Fatal Error発生時のエラーメッセージ

PHP 5系までの場合
Fatal error: Call to undefined function showMessage() in

PHP 7系〜の場合
Fatal error: Uncaught Error: Call to undefined function showMessage() in
(キャッチされていないErrorクラスというメッセージ)

set_exception_handlerを定義しない場合や、例外に変換できない致命的なエラーは後述のregister_shutdown_functionで最終的に処理します。

【プログラム停止時の処理】register_shutdown_function

register_shutdown_function関数を登録することで、例外に変換されない致命的なエラーが発生した場合の処理を行うことができます。

register_shutdown_function(
    function() {
        $error = error_get_last();

        // 処理が正常に完了
        if (is_null($error)) {
            return;
        }

        // 停止時の処理
        echo '処理を停止: message: ' . $error['message'] . ' fle: ' . $error['file'] . ' line: ' . $error['line'];
    }
);

register_shutdown_functionは致命的なエラー発生時以外にも、処理が正常に終了したときやexitを実行した際にも呼び出されます。

コールバック関数内部でerror_get_last関数を利用することで、最後に発生したエラーの情報を取得します。

捕捉手段のないエラー、例外

最後に、以下は上記で紹介したいずれのハンドラーでも捕捉できないエラー、例外の発生パターンとなります。

・各ハンドラーを登録する前に発生した場合
・ハンドラー自体の内部で起きた場合
・Parse error(パースエラー)などプログラムそのものを実行できない場合

Follow me!