Laravel - 27. エラー処理 - Exceptionハンドラ

引き続きLaravelのエラー処理について学習していきましょう。ここではExceptionハンドラについて取り上げます。Exceptionハンドラとはスローされた例外を処理する仕組みです。たとえば前節では ModelNotFoundException という例外がスローされていましたが、Exceptionハンドラを実装することでこのような例外インスタンスを適切に処理できるようになります。

Exceptionハンドラはデフォルトで app/Exceptions フォルダ下に Handler.php という名前で用意されています。テキストエディタで app/Exceptions/Handler.php ファイルを開いてみましょう。

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    protected $dontReport = [
        //
    ];

    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    public function report(Exception $exception)
    {
        parent::report($exception);
    }

    public function render($request, Exception $exception)
    {
        return parent::render($request, $exception);
    }
}

上記のように $dontReport$dontFlash という2つのプロパティと reportrender と2つのメソッドが定義されています。2つのプロパティはレポート出力やフラッシュを抑制するためのもので、 report メソッドには例外発生時のログ出力やレポートの送信などを実装し、 render メソッドには例外発生時のレスポンスの出力を実装します。

ここでは次のように report メソッドと render メソッドを実装します。

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Log;

class Handler extends ExceptionHandler
{
    # 省略...

    public function report(Exception $exception)
    {
        if ($exception instanceof ModelNotFoundException) {
            Log::warning("ModelNotFoundException");
        }
        parent::report($exception);
    }

    public function render($request, Exception $exception)
    {
        if ($exception instanceof ModelNotFoundException) {
            return redirect("/hello");
        }
        return parent::render($request, $exception);
    }
}

まずプログラムの先頭部分で use キーワードを使って ModelNotFoundExceptionLog をインポートしています。

use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Log;

report メソッドの中では ModelNotFoundException がスローされた場合に WARNING ログを出力しています。また render メソッドの中では ModelNotFoundException がスローされた場合に "/hello" にリダイレクトするように実装しています。

動作確認

それでは Handler.php ファイルを追加したので、PHPのビルトインWebサーバを使ってWebアプリケーションを起動してみましょう。次のようにコマンドを入力します。

$ php artisan serve --host 0.0.0.0
Laravel development server started: http://0.0.0.0:8000

次にアドレスバーから以下のURLにアクセスしてみましょう。

http://localhost:8000/hello/show/100

実行結果のようにデータベースに存在しない id を指定した場合は HelloControllershow アクションから ModelNotFoundException がスローされます。スローされた ModelNotFoundExceptionHandler クラスの report メソッド、 render メソッドで処理されるため最終的に "/hello" にリダイレクトされます。

また report メソッドによってログが出力されていることも確認しておきましょう。テキストエディタで storage/logs/laravel.log ファイルを開いてみましょう。

[2020-09-08 02:31:12] local. WARNING: ModelNotFoundException  

Handler クラスの report メソッドによって WARNING ログが出力されているのがわかります。

まとめ

  • Laravelの例外処理は app/Exceptions/Handler.php ファイルでカスタマイズできる
  • Handler クラス にはレポートの記録やログ出力用の report メソッド、画面表示用の render メソッドが用意されている
  • report メソッドや render メソッドをオーバーライドすることで例外処理をカスタマイズできる