Laravel 12 イベントとリスナー完全ガイド:イベント駆動アーキテクチャの実装と面接対策
Laravel 12のイベント・リスナーシステムを徹底解説。自動検出機能、キュー処理、トランザクション対応、ユニークリスナーの実装方法から、技術面接でよく問われるイベント駆動アーキテクチャの質問まで網羅的に解説します。

Laravelのイベントとリスナーは、オブザーバーパターンを実装し、アプリケーションの各コンポーネントを疎結合に保つ仕組みです。ユーザーが注文を行うとOrderShippedイベントが発火し、通知送信、分析データ収集、在庫更新といった処理が、それぞれ独立したリスナーで実行されます。
Laravel 12では、app/Listenersディレクトリ内のリスナーが自動的に検出されます。イベントクラスをタイプヒントしたhandleまたは__invokeメソッドを持つクラスは、設定ファイルなしで自動登録されます。
Laravel 12 におけるイベント自動検出の仕組み
Laravel 11以降、EventServiceProviderは廃止されました。LaravelはListenersディレクトリをスキャンし、リフレクションを使用してhandleメソッドのタイプヒントから、各リスナーが応答するイベントを特定します。
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
class SendOrderConfirmation
{
public function handle(OrderShipped $event): void
{
// $event->order->user に確認メールを送信
}
}上記のリスナーは、OrderShippedイベントに対して自動的に登録されます。サービスプロバイダでの手動バインディングは不要です。これによりボイラープレートコードが削減され、イベントとリスナーの関係が実装コードの近くに保たれます。
登録済みリスナーを確認するには、php artisan event:listを実行します。本番環境では、php artisan event:cacheでイベントマニフェストをキャッシュし、リクエストごとのディレクトリスキャンを省略できます。
Artisan によるイベントとリスナーの作成
Laravelは、イベントとリスナーの雛形を生成するArtisanコマンドを提供しています。
# イベントクラスを生成
php artisan make:event OrderShipped
# イベントに紐づくリスナーを生成
php artisan make:listener SendShipmentNotification --event=OrderShipped生成されるイベントクラスは3つのトレイトを使用します。Dispatchableは静的dispatch()メソッドを提供し、InteractsWithSocketsはブロードキャスト用、SerializesModelsはリスナーがキューに入る際のEloquentモデルのシリアライズを担当します。
<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Queue\SerializesModels;
class OrderShipped
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(
public Order $order,
) {}
}イベントクラスはデータコンテナです。Orderモデルを保持するだけで、ビジネスロジックはリスナーに記述します。
コントローラとサービスからのイベント発火
イベントクラスの静的dispatch()メソッドを使用してイベントを発火します。
<?php
namespace App\Http\Controllers;
use App\Events\OrderShipped;
use App\Models\Order;
use Illuminate\Http\Request;
class OrderController extends Controller
{
public function ship(Request $request, Order $order)
{
// 出荷処理...
OrderShipped::dispatch($order);
return redirect()->route('orders.index');
}
}条件付きでイベントを発火する場合は、dispatchIf()またはdispatchUnless()を使用します。
// 追跡番号がある場合のみ発火
OrderShipped::dispatchIf($order->tracking_number !== null, $order);Laravelの面接対策はできていますか?
インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。
重い処理のためのキュー対応リスナー
メール送信、外部API呼び出し、重い計算処理を行うリスナーは、非同期で実行する必要があります。ShouldQueueインターフェースを実装することで、リスナーをキューにプッシュできます。
<?php
namespace App\Listeners;
use App\Events\OrderShipped;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendShipmentNotification implements ShouldQueue
{
public $queue = 'notifications';
public $delay = 60; // 処理前に60秒待機
public function handle(OrderShipped $event): void
{
// $event->order->user に通知を送信
}
}キュー接続と名前は$connectionと$queueプロパティでカスタマイズするか、ランタイムメソッドを使用します。
public function viaConnection(): string
{
return 'redis';
}
public function viaQueue(): string
{
return $this->event->order->priority === 'high'
? 'high-priority'
: 'default';
}shouldQueue による条件付きキューイング
イベントデータに基づいてキューイングを判断する場合があります。
public function shouldQueue(OrderShipped $event): bool
{
// 100ドル以上の注文のみキューに入れる
return $event->order->total >= 10000;
}データベーストランザクションとイベントタイミング
トランザクション内で発火されたキュー対応リスナーは、トランザクションがコミットされる前に処理される可能性があり、データ不整合エラーが発生することがあります。2つの解決策があります。
1. グローバル設定 config/queue.phpで設定する方法:
'connections' => [
'redis' => [
'after_commit' => true,
],
],2. リスナー単位 ShouldQueueAfterCommitを使用する方法:
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;
class UpdateInventory implements ShouldQueueAfterCommit
{
public function handle(OrderShipped $event): void
{
// 注文のクエリは安全、トランザクションはコミット済み
}
}イベント自体に対しては、イベントクラスでShouldDispatchAfterCommitを実装します。
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
class OrderShipped implements ShouldDispatchAfterCommit
{
// トランザクションコミット後にのみイベントが発火
}重複を防ぐユニークリスナー
ShouldBeUniqueインターフェースは、同一のリスナーが処理中に重複してキューに入ることを防ぎます。
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
class ProcessLicenseKey implements ShouldQueue, ShouldBeUnique
{
public $uniqueFor = 3600; // ロックは1時間後に期限切れ
public function uniqueId(LicensePurchased $event): string
{
return 'license:' . $event->license->id;
}
public function handle(LicensePurchased $event): void
{
// ライセンスキーを生成して割り当て
}
}同じライセンスIDで複数のイベントが短時間に発火された場合、最初のリスナーのみが処理されます。後続の試行はロックが保持されていることを検出してキューイングをスキップします。
関連イベントのためのイベントサブスクライバ
複数の関連イベントが共通の処理ロジックを共有する場合、イベントサブスクライバは複数のハンドラを1つのクラスにまとめます。
<?php
namespace App\Listeners;
use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;
use Illuminate\Events\Dispatcher;
class UserActivitySubscriber
{
public function handleLogin(Login $event): void
{
// ログイン成功をログに記録、last_loginタイムスタンプを更新
}
public function handleLogout(Logout $event): void
{
// ログアウトをログに記録、セッションデータをクリア
}
public function subscribe(Dispatcher $events): array
{
return [
Login::class => 'handleLogin',
Logout::class => 'handleLogout',
];
}
}サブスクライバも自動検出ルールに従います。ハンドラメソッドが適切にタイプヒントされたパラメータを持っていれば、Laravelが自動的に登録します。
Union Types による複数イベントの処理
PHP 8のUnion Typesを使用して、1つのリスナーで複数のイベントタイプに応答できます。
public function handle(OrderShipped|OrderCancelled $event): void
{
match (true) {
$event instanceof OrderShipped => $this->notifyShipped($event),
$event instanceof OrderCancelled => $this->notifyCancelled($event),
};
}このパターンは、異なるイベントタイプで類似のロジックをたどる通知に適しています。
Event::defer によるイベントの遅延発火
Laravel 12では、コードブロックの完了後までイベント発火を遅延させるEvent::defer()が導入されました。これにより、リスナーがすべての関連レコードにアクセスできることが保証されます。
use Illuminate\Support\Facades\Event;
Event::defer(function () {
$user = User::create(['name' => 'John']);
$user->posts()->create(['title' => 'Welcome']);
});
// UserとPostの作成イベントがここで発火クロージャ内で例外が発生した場合、遅延されたイベントは発火されません。
今すぐ練習を始めましょう!
面接シミュレーターと技術テストで知識をテストしましょう。
Laravel イベント・リスナーの面接質問
技術面接では、イベント駆動アーキテクチャの理解度がよく問われます。以下は、経験豊富なLaravel開発者を見分ける質問です。
Q: Laravel 12はEventServiceProviderなしでどのようにイベントリスナーを登録しますか?
Laravelはリフレクションを使用してapp/Listenersをスキャンします。handle()または__invoke()メソッドのタイプヒントを読み取り、各リスナーが応答するイベントを特定します。本番環境ではphp artisan event:cacheでマニフェストをキャッシュします。
Q: リスナーがShouldQueueを実装すべきタイミングは?
処理に数ミリ秒以上かかる場合です。メール送信、外部API呼び出し、レポート生成、ファイル処理などが該当します。同期リスナーはHTTPレスポンスをブロックします。
Q: ShouldQueueAfterCommitが解決する問題は何ですか?
キュー対応リスナーは、データベーストランザクションがコミットされる前に処理される可能性があります。リスナーが作成されたばかりのレコードをクエリすると、データがまだコミットされていないため失敗します。ShouldQueueAfterCommitはトランザクション完了までキューへのディスパッチを遅延させます。
Q: 同一イベントの重複処理をどのように防ぎますか?
ShouldBeUniqueを実装します。uniqueId()を定義してイベントデータに基づくキャッシュキーを返します。リスナーはアトミックロックを取得し、ロックが保持されている場合は重複ディスパッチがスキップされます。
Q: イベントリスナーとイベントサブスクライバの違いは何ですか?
リスナーは1つのイベントタイプを処理します。サブスクライバは、複数の関連イベントのハンドラを1つの場所に登録するクラスで、認証イベントや監査ログのグループ化に有用です。
スケーラブルアプリケーションにおけるLaravelイベントの意義
- イベントはコンポーネントを疎結合にし、通知や分析などの機能が独立して進化できるようにする
- キュー対応リスナーは重い処理をオフロードし、HTTPレスポンスを高速に保つ
ShouldQueueAfterCommitはキューワーカーとデータベーストランザクション間の競合状態を防ぐ- Laravel 12の自動検出は設定のオーバーヘッドを排除し、リスナーロジックを実装に近く保つ
- イベントサブスクライバは、ユーザーアクティビティトラッキングなどの一般的なパターンの関連イベント処理を統合し、ファイルの散在を減らす
- SharpSkillの
/technologies/laravel/interview-questions/events-listenersモジュールでは、これらのパターンをインタラクティブな質問で学習できます
Laravel のバグを見つけられますか
実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

執筆
Anthony Fillion-MailletSharpSkill 創業者
10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。
2026年8月20日 更新
タグ
共有
関連記事

Laravel ソリューション: 高度なパターン、デバッグ、面接対策 2026年版
Laravel の高度なアーキテクチャパターン、デバッグ手法、面接対策を網羅的に解説。サービスクラス、リポジトリパターン、Telescope によるデバッグ、Laravel 開発者向けの頻出面接質問を詳しく説明します。

Laravel 12 新機能まとめ|スターターキット刷新・WorkOS連携・面接対策【2026年最新版】
Laravel 12の新機能を徹底解説。Breeze/Jetstreamに代わる新スターターキット、WorkOS AuthKit統合、Carbon 3対応、アップグレード手順、2026年版面接質問まで網羅的に紹介します。

Laravel Middleware徹底解説:認証、レート制限、カスタムミドルウェアの実装ガイド
Laravelミドルウェアの仕組みを基礎から応用まで解説します。認証ミドルウェア、throttleによるレート制限、カスタムミドルウェアの作成方法、そして本番環境で使える実践的なミドルウェアパターンを具体的なコード例とともに紹介します。