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つのプロパティと report 、 render と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 キーワードを使って ModelNotFoundException と Log をインポートしています。
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 を指定した場合は HelloController の show アクションから ModelNotFoundException がスローされます。スローされた ModelNotFoundException は Handler クラスの 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メソッドをオーバーライドすることで例外処理をカスタマイズできる