Laravelでカスタム例外クラスを作成する方法!初心者向け完全ガイド
生徒
「Laravelでエラーが起きたとき、自分でオリジナルのエラーを作って管理することってできますか?」
先生
「できますよ。カスタム例外クラスを作ることで、自分のアプリに合ったエラーを独自に定義して、わかりやすく管理できるようになります。」
生徒
「難しそうですが、初心者でも作れますか?」
先生
「手順はシンプルです。実際のコードを見ながら一つずつ進めていきましょう!」
1. カスタム例外クラスとは何か?
Laravelにはあらかじめさまざまなエラーの種類が用意されています。たとえば「データが見つからなかった」「認証に失敗した」などはLaravelが最初から持っているエラーです。しかし自分で作るアプリには、それだけでは表現しきれない独自のエラーが出てくることがあります。
そういったときに役立つのがカスタム例外クラスです。例外クラスとは、エラーの種類に名前をつけて、どんな情報を持たせるかをまとめた設計図のようなものです。自分でオリジナルのエラーを作ることで、「このエラーは何が起きたのか」がコードを読んだだけですぐにわかるようになります。
身近なもので例えると、病院の診断書のようなイメージです。「体調が悪い」という一言ではなく「インフルエンザ」「骨折」のように具体的な名前をつけることで、どんな対処が必要かが一目でわかります。カスタム例外クラスも同じで、エラーに具体的な名前をつけることでコードの整理がしやすくなります。
2. Artisanコマンドでカスタム例外クラスを生成する
Laravelでカスタム例外クラスを作るには、Artisanコマンドを使うのが最も簡単な方法です。Artisanコマンドとは、Laravelに標準で備わっているコマンドラインツールで、ファイルの自動生成や各種作業をターミナルから素早く行える機能です。ターミナルとは、パソコンに文字を打ち込んで命令を実行する画面のことです。
たとえば「在庫不足エラー」を表すカスタム例外クラスを作りたい場合は、以下のコマンドを実行します。
// ターミナルで実行するコマンド
php artisan make:exception OutOfStockException
このコマンドを実行すると、app/Exceptions/OutOfStockException.phpというファイルが自動的に作成されます。ファイル名のOutOfStockExceptionは「在庫切れ例外」という意味で、末尾にExceptionとつけるのがLaravelの慣習です。慣習とは、みんながそうしましょうと決めているルールのことです。
生成されたファイルを開くと、最初は以下のようなシンプルな内容になっています。
<?php
namespace App\Exceptions;
use Exception;
class OutOfStockException extends Exception
{
// ここにカスタムの処理を書いていく
}
extends Exceptionとは「Exceptionクラスを引き継いで使う」という意味です。extends(継承)とは、親となるクラスの機能をそのまま受け継いで新しいクラスを作ることです。これによりOutOfStockExceptionはExceptionが持つ基本的なエラー機能をすべて使いながら、独自の機能を追加できます。
3. カスタム例外クラスに独自のメッセージとコードを設定する
生成されたカスタム例外クラスには、独自のメッセージやエラーコードを設定することができます。クラスに__construct()というメソッド(処理のまとまり)を書くことで、例外が発生したときに最初に実行される初期設定を定義できます。
__construct()は「コンストラクタ」とも呼ばれ、クラスが作られた瞬間に自動で実行される処理です。家で例えると、家を建てたときに最初に電気や水道を通す工事のようなものです。
<?php
namespace App\Exceptions;
use Exception;
class OutOfStockException extends Exception
{
// コンストラクタ:例外が発生したときに自動で実行される
public function __construct(string $productName)
{
$message = $productName . 'の在庫が不足しています。';
parent::__construct($message, 400);
}
}
parent::__construct()は親クラスであるExceptionのコンストラクタを呼び出すものです。第一引数にエラーメッセージ、第二引数にエラーコードを渡します。このようにすることで、商品名を受け取って「〇〇の在庫が不足しています」という具体的なメッセージを自動で作るカスタム例外が完成します。
4. カスタム例外クラスをコントローラーで発生させる方法
作成したカスタム例外クラスは、コントローラー(処理を担当するファイル)の中でthrowを使って発生させます。throwとは「投げる」という意味の英語で、プログラム上では「この例外を起こしてください」という合図です。
在庫確認の処理を例にすると、以下のように使います。
<?php
namespace App\Http\Controllers;
use App\Exceptions\OutOfStockException;
use Illuminate\Http\Request;
class OrderController extends Controller
{
public function store(Request $request)
{
$productName = $request->input('product_name');
$stock = 0; // 在庫数(仮に0とする)
// 在庫が0以下なら例外を発生させる
if ($stock <= 0) {
throw new OutOfStockException($productName);
}
return response()->json(['message' => '注文が完了しました。']);
}
}
throw new OutOfStockException($productName)と書くことで、在庫が0のときに先ほど作ったカスタム例外が発生します。newはクラスから実体を作るためのキーワードです。このように例外に意味のある名前をつけておくことで、コードを読んだときに「在庫不足でエラーになった」とすぐに判断できます。
5. Handler.phpでカスタム例外をキャッチして処理する
カスタム例外を発生させるだけでなく、それを受け取ってどう対処するかも大切です。app/Exceptions/Handler.phpのregister()メソッド内に処理を書くことで、カスタム例外が起きたときの動作を自由に設定できます。
キャッチとは、投げられた例外を受け取って対処することを意味します。throwとcatchはセットで覚えておきましょう。
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use App\Exceptions\OutOfStockException;
class Handler extends ExceptionHandler
{
public function register(): void
{
$this->renderable(function (OutOfStockException $e, $request) {
if ($request->expectsJson()) {
// APIアクセスのときはJSONで返す
return response()->json([
'status' => 'error',
'message' => $e->getMessage(),
], 400);
}
// 通常のアクセスのときはエラーページを表示
return response()->view('errors.out-of-stock', [
'message' => $e->getMessage(),
], 400);
});
}
}
$e->getMessage()は例外に設定されたメッセージを取り出すメソッドです。このようにHandler.phpに書いておくことで、OutOfStockExceptionが発生するたびに自動的にこの処理が動き、APIにはJSON、通常のページには専用のエラー画面を返すことができます。
6. render()メソッドをカスタム例外クラス自体に書く方法
Handler.phpに処理をまとめる方法のほかに、カスタム例外クラス自体にrender()メソッドを書くスタイルもあります。この方法だと、例外クラスを見るだけで「この例外が起きたらどんな画面を返すか」がわかるため、コードが読みやすくなるという利点があります。
Laravelは例外クラスにrender()メソッドがある場合、Handler.phpより優先してそちらを実行します。例外クラスの中に直接レスポンスの処理を書きたい場合は、以下のようにします。
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
class OutOfStockException extends Exception
{
public function __construct(string $productName)
{
parent::__construct($productName . 'の在庫が不足しています。', 400);
}
// この例外が発生したときのレスポンスをここに書く
public function render(Request $request)
{
return response()->json([
'status' => 'error',
'message' => $this->getMessage(),
], 400);
}
}
$this->getMessage()は自分自身が持つメッセージを取り出す書き方です。$thisとは「このクラス自身」を指すキーワードです。例外クラスの中にrender()を書くスタイルは、例外の数が増えてきたときにHandler.phpがごちゃごちゃしにくいという点で、多くの開発現場でも採用されています。
7. カスタム例外クラスを使うメリットと活用場面
カスタム例外クラスを作る最大のメリットは、コードの可読性と保守性が上がることです。可読性とはコードの読みやすさ、保守性とはあとから修正・追加しやすいかどうかのことです。
たとえばチームで開発しているとき、コードにthrow new OutOfStockException()と書いてあれば、見た人は「在庫不足のエラーが起きる可能性がある処理だ」とすぐにわかります。一方でthrow new Exception('エラーが発生しました')とだけ書かれていても、何のエラーなのかが読み取りにくくなります。
カスタム例外クラスが特に役立つ場面としては、決済処理の失敗、会員限定コンテンツへの不正アクセス、外部サービスとの連携エラー、ファイルのアップロード失敗など、アプリ独自のビジネスロジックに関わるエラーが挙げられます。ビジネスロジックとは、そのサービス特有のルールや処理のことです。これらをそれぞれ独立したカスタム例外クラスとして定義しておくことで、エラー処理が整理されてバグの特定もしやすくなります。