Laravel Events та Listeners у 2026: Подієва Архітектура та Питання на Співбесідах

Повний посібник з системи подій та слухачів у Laravel 12. Реалізація патерну спостерігача, черги для listeners, транзакції бази даних та питання на технічних співбесідах.

Laravel Events та Listeners - подієва архітектура

Система подій та слухачів у Laravel реалізує патерн спостерігача, розділяючи компоненти додатку шляхом надання різним частинам системи можливості реагувати на дії без прямих залежностей. Коли користувач оформлює замовлення, подія OrderShipped викликається, а окремі слухачі обробляють сповіщення, аналітику та оновлення складу незалежно один від одного.

Автоматичне Виявлення Подій у Laravel 12

Laravel 12 автоматично виявляє слухачів у директорії app/Listeners. Будь-який клас із методом handle або __invoke, що має type hint на клас події, автоматично реєструється без конфігураційного файлу.

Як Працює Автоматичне Виявлення Подій у Laravel 12

Починаючи з Laravel 11, EventServiceProvider більше не існує. Фреймворк сканує директорію Listeners та використовує рефлексію для визначення, на які події реагує кожен слухач, базуючись на type hint у сигнатурі методу handle.

app/Listeners/SendOrderConfirmation.phpphp
<?php

namespace App\Listeners;

use App\Events\OrderShipped;

class SendOrderConfirmation
{
    public function handle(OrderShipped $event): void
    {
        // Надіслати підтверджуючий email на $event->order->user
    }
}

Наведений вище слухач автоматично реєструється для подій OrderShipped. Це не потребує ручного зв'язування в service provider. Такий підхід зменшує шаблонний код та зберігає зв'язки подія-слухач близько до коду, що їх реалізує.

Для перевірки зареєстрованих слухачів виконайте php artisan event:list. У продакшн середовищі закешуйте маніфест подій командою php artisan event:cache, щоб уникнути сканування директорії при кожному запиті.

Створення Подій та Слухачів за Допомогою Artisan

Laravel надає команди Artisan для генерації каркасу подій та слухачів:

bash
# Згенерувати клас події
php artisan make:event OrderShipped

# Згенерувати слухача, прив'язаного до події
php artisan make:listener SendShipmentNotification --event=OrderShipped

Згенерований клас події використовує три трейти: Dispatchable для статичного методу dispatch(), InteractsWithSockets для broadcasting та SerializesModels для серіалізації моделей Eloquent, коли слухачі додаються до черги.

app/Events/OrderShipped.phpphp
<?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() на класі події:

app/Http/Controllers/OrderController.phpphp
<?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():

php
// Відправляти тільки якщо замовлення має номер відстеження
OrderShipped::dispatchIf($order->tracking_number !== null, $order);

Готовий до співбесід з Laravel?

Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.

Черги для Слухачів Повільних Операцій

Слухачі, що відправляють електронну пошту, викликають зовнішні API або виконують важкі обчислення, повинні працювати асинхронно. Імплементація ShouldQueue додає слухача до черги:

app/Listeners/SendShipmentNotification.phpphp
<?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, або через методи runtime:

php
public function viaConnection(): string
{
    return 'redis';
}

public function viaQueue(): string
{
    return $this->event->order->priority === 'high' 
        ? 'high-priority' 
        : 'default';
}

Умовне Додавання до Черги з shouldQueue

Іноді слухач повинен додаватися до черги лише на основі даних події:

php
public function shouldQueue(OrderShipped $event): bool
{
    // Додавати до черги тільки для замовлень понад 100$
    return $event->order->total >= 10000;
}

Транзакції Бази Даних та Час Подій

Слухачі з черги, відправлені всередині транзакції, можуть бути оброблені до того, як транзакція буде закомічена, що спричиняє помилки відсутніх даних. Існують два рішення:

1. Глобальне налаштування в config/queue.php:

php
'connections' => [
    'redis' => [
        'after_commit' => true,
    ],
],

2. Для окремого слухача з ShouldQueueAfterCommit:

php
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;

class UpdateInventory implements ShouldQueueAfterCommit
{
    public function handle(OrderShipped $event): void
    {
        // Безпечно запитувати замовлення, транзакція закомічена
    }
}

Для самих подій імплементуйте ShouldDispatchAfterCommit на класі події:

php
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;

class OrderShipped implements ShouldDispatchAfterCommit
{
    // Подія відправляється тільки після коміту транзакції
}

Унікальні Слухачі для Запобігання Дублікатам

Інтерфейс ShouldBeUnique запобігає додаванню дублікатів слухачів до черги, поки один вже обробляється:

php
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 ліцензії швидко викликає кілька подій, обробляється лише перший слухач. Наступні спроби виявляють, що блокування утримується, і пропускають додавання до черги.

Підписники Подій для Пов'язаних Подій

Коли кілька пов'язаних подій мають спільну логіку обробки, підписники подій групують обробники в одному класі:

app/Listeners/UserActivitySubscriber.phpphp
<?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

Один слухач може реагувати на кілька типів подій, використовуючи union types з PHP 8:

php
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() для відкладення відправки подій до завершення блоку коду. Це гарантує слухачам доступ до всіх пов'язаних записів:

php
use Illuminate\Support\Facades\Event;

Event::defer(function () {
    $user = User::create(['name' => 'John']);
    $user->posts()->create(['title' => 'Welcome']);
});
// Події для створення User і Post відправляються тут

Якщо всередині closure виникає виключення, відкладені події ніколи не відправляються.

Починай практикувати!

Перевір свої знання з нашими симуляторами співбесід та технічними тестами.

Питання на Співбесідах про Laravel Events та Listeners

Технічні співбесіди часто перевіряють розуміння подієвої архітектури. Ось питання, які відрізняють досвідчених Laravel розробників:

П: Як Laravel 12 реєструє слухачів без EventServiceProvider?

Laravel сканує app/Listeners за допомогою рефлексії. Він читає type hint на методах handle() або __invoke(), щоб визначити, на яку подію реагує кожен слухач. У продакшні закешуйте маніфест командою php artisan event:cache.

П: Коли слухач повинен імплементувати ShouldQueue?

Завжди, коли операція займає більше кількох мілісекунд: відправка email, виклик зовнішніх API, генерація звітів або обробка файлів. Синхронні слухачі блокують HTTP відповідь.

П: Яку проблему вирішує ShouldQueueAfterCommit?

Слухачі з черги можуть бути оброблені до того, як транзакція бази даних буде закомічена. Якщо слухач запитує щойно створений запис, це завершиться невдачею, оскільки дані ще не закомічені. ShouldQueueAfterCommit відкладає відправку до черги до завершення транзакції.

П: Як запобігти дублюванню обробки тієї ж події?

Імплементуйте ShouldBeUnique. Визначте uniqueId() для повернення ключа кешу на основі даних події. Слухач отримує атомарне блокування, і дублікати відправок пропускаються, якщо блокування утримується.

П: Яка різниця між слухачем подій та підписником подій?

Слухач обробляє один тип події. Підписник — це клас, який реєструє обробники для кількох пов'язаних подій в одному місці, корисний для групування подій автентифікації або аудит-логування.

Значення Laravel Events для Масштабованих Додатків

  • Події розділяють компоненти, дозволяючи функціям на кшталт сповіщень та аналітики розвиватися незалежно
  • Слухачі з черги переносять повільні операції, зберігаючи швидкі HTTP відповіді
  • ShouldQueueAfterCommit запобігає race conditions між воркерами черги та транзакціями бази даних
  • Автоматичне виявлення в Laravel 12 усуває конфігураційні накладні витрати, зберігаючи логіку слухачів близько до реалізації
  • Підписники подій консолідують обробку пов'язаних подій, зменшуючи розкидання файлів для поширених патернів, таких як відстеження активності користувача
  • Модуль /technologies/laravel/interview-questions/events-listeners на SharpSkill охоплює ці патерни з інтерактивними питаннями
Щоденний виклик

Чи знайдеш ти помилку в Laravel?

Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Anthony Fillion-Maillet

Автор:

Anthony Fillion-Maillet

Засновник SharpSkill

Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.

Оновлено 20 серпня 2026 р.

Теги

#laravel
#events
#listeners
#php
#подієва архітектура

Поділитися

Пов'язані статті