Eventos e Listeners no Laravel 2026: Arquitetura Event-Driven e Perguntas de Entrevista

Domine eventos e listeners do Laravel com a descoberta automática do Laravel 12, listeners assíncronos e padrões de arquitetura event-driven para entrevistas técnicas.

Eventos e listeners Laravel arquitetura event-driven

Eventos e listeners do Laravel implementam o padrão Observer, desacoplando componentes ao permitir que diferentes partes de uma aplicação reajam a ações sem dependências diretas. Quando um usuário realiza um pedido, o evento OrderShipped é disparado, e listeners separados tratam notificações, analytics e atualizações de inventário de forma independente.

Descoberta Automática no Laravel 12

O Laravel 12 descobre automaticamente os listeners em app/Listeners. Qualquer classe com um método handle ou __invoke que tenha type hint de um evento é registrada automaticamente, sem necessidade de arquivo de configuração.

Como Funciona a Descoberta de Eventos no Laravel 12

Desde o Laravel 11, o EventServiceProvider não existe mais. O Laravel escaneia o diretório Listeners e usa reflection para determinar quais eventos cada listener trata, baseando-se no type hint da assinatura do método handle.

app/Listeners/SendOrderConfirmation.phpphp
<?php

namespace App\Listeners;

use App\Events\OrderShipped;

class SendOrderConfirmation
{
    public function handle(OrderShipped $event): void
    {
        // Enviar email de confirmação para $event->order->user
    }
}

O listener acima é automaticamente registrado para eventos OrderShipped. Não é necessário binding manual em um service provider. Essa abordagem reduz código repetitivo e mantém as relações evento-listener próximas do código que as implementa.

Para verificar os listeners registrados, executar php artisan event:list. Em produção, fazer cache do manifesto com php artisan event:cache para evitar o escaneamento do diretório em cada requisição.

Criação de Eventos e Listeners com Artisan

O Laravel fornece comandos Artisan para gerar eventos e listeners:

bash
# Gerar uma classe de evento
php artisan make:event OrderShipped

# Gerar um listener vinculado a um evento
php artisan make:listener SendShipmentNotification --event=OrderShipped

A classe de evento gerada usa três traits: Dispatchable para o método estático dispatch(), InteractsWithSockets para broadcasting, e SerializesModels para serializar models Eloquent quando os listeners estão na fila.

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,
    ) {}
}

A classe de evento é um container de dados. Ela contém o model Order e nada mais. A lógica de negócio pertence aos listeners, não aos eventos.

Dispatch de Eventos a partir de Controllers e Services

Disparar eventos usando o método estático dispatch() na classe de evento:

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)
    {
        // Lógica de envio aqui...
        
        OrderShipped::dispatch($order);
        
        return redirect()->route('orders.index');
    }
}

Para dispatch condicional, usar dispatchIf() ou dispatchUnless():

php
// Disparar apenas se o pedido tiver número de rastreamento
OrderShipped::dispatchIf($order->tracking_number !== null, $order);

Pronto para mandar bem nas entrevistas de Laravel?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Listeners Assíncronos para Operações Lentas

Listeners que enviam emails, chamam APIs externas ou realizam cálculos pesados devem executar de forma assíncrona. Implementar ShouldQueue para colocar o listener na fila:

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; // Aguardar 60 segundos antes de processar

    public function handle(OrderShipped $event): void
    {
        // Enviar notificação para $event->order->user
    }
}

Personalizar a conexão e nome da fila com as propriedades $connection e $queue, ou usar métodos dinâmicos:

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

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

Fila Condicional com shouldQueue

Às vezes um listener só deve ser enfileirado com base nos dados do evento:

php
public function shouldQueue(OrderShipped $event): bool
{
    // Enfileirar apenas para pedidos acima de R$100
    return $event->order->total >= 10000;
}

Transações de Banco de Dados e Timing de Eventos

Listeners na fila despachados dentro de uma transação podem ser processados antes do commit da transação, causando erros de dados ausentes. Existem duas soluções:

1. Configuração global em config/queue.php:

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

2. Por listener com ShouldQueueAfterCommit:

php
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;

class UpdateInventory implements ShouldQueueAfterCommit
{
    public function handle(OrderShipped $event): void
    {
        // Seguro para consultar o pedido, transação commitada
    }
}

Para os próprios eventos, implementar ShouldDispatchAfterCommit na classe de evento:

php
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;

class OrderShipped implements ShouldDispatchAfterCommit
{
    // O evento só é despachado após o commit da transação
}

Listeners Únicos para Evitar Duplicatas

A interface ShouldBeUnique impede que listeners duplicados sejam enfileirados enquanto outro está processando:

php
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessLicenseKey implements ShouldQueue, ShouldBeUnique
{
    public $uniqueFor = 3600; // O lock expira após 1 hora

    public function uniqueId(LicensePurchased $event): string
    {
        return 'license:' . $event->license->id;
    }

    public function handle(LicensePurchased $event): void
    {
        // Gerar e atribuir chave de licença
    }
}

Se o mesmo ID de licença dispara múltiplos eventos rapidamente, apenas o primeiro listener processa. Tentativas subsequentes encontram o lock ativo e pulam o enfileiramento.

Event Subscribers para Eventos Relacionados

Quando múltiplos eventos relacionados compartilham lógica de tratamento comum, os event subscribers agrupam handlers em uma única classe:

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
    {
        // Registrar login bem-sucedido, atualizar last_login
    }

    public function handleLogout(Logout $event): void
    {
        // Registrar logout, limpar dados de sessão
    }

    public function subscribe(Dispatcher $events): array
    {
        return [
            Login::class => 'handleLogin',
            Logout::class => 'handleLogout',
        ];
    }
}

Os subscribers seguem as regras de descoberta automática. Se os métodos handler estão na classe subscriber com parâmetros corretamente tipados, o Laravel os registra automaticamente.

Ouvir Múltiplos Eventos com Union Types

Um único listener pode responder a múltiplos tipos de eventos usando union types do PHP 8:

php
public function handle(OrderShipped|OrderCancelled $event): void
{
    match (true) {
        $event instanceof OrderShipped => $this->notifyShipped($event),
        $event instanceof OrderCancelled => $this->notifyCancelled($event),
    };
}

Esse padrão funciona bem para notificações que seguem lógica similar entre diferentes tipos de eventos.

Adiar Eventos com Event::defer

O Laravel 12 introduziu Event::defer() para atrasar o dispatch de eventos até que um bloco de código complete. Isso garante que os listeners tenham acesso a todos os registros relacionados:

php
use Illuminate\Support\Facades\Event;

Event::defer(function () {
    $user = User::create(['name' => 'John']);
    $user->posts()->create(['title' => 'Welcome']);
});
// Os eventos para User e Post são despachados aqui

Se uma exceção ocorre dentro da closure, os eventos adiados nunca são despachados.

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Perguntas de Entrevista sobre Eventos e Listeners do Laravel

Entrevistas técnicas frequentemente avaliam a compreensão de arquitetura event-driven. Estas são perguntas que distinguem desenvolvedores Laravel experientes:

P: Como o Laravel 12 registra event listeners sem EventServiceProvider?

O Laravel escaneia app/Listeners usando reflection. Ele lê o type hint nos métodos handle() ou __invoke() para determinar a qual evento cada listener responde. Fazer cache do manifesto em produção com php artisan event:cache.

P: Quando um listener deve implementar ShouldQueue?

Quando a operação leva mais do que alguns milissegundos: envio de emails, chamadas a APIs externas, geração de relatórios, ou processamento de arquivos. Listeners síncronos bloqueiam a resposta HTTP.

P: Qual problema o ShouldQueueAfterCommit resolve?

Listeners na fila podem ser processados antes do commit da transação do banco de dados. Se o listener consulta um registro recém-criado, ele falha porque os dados ainda não foram commitados. ShouldQueueAfterCommit atrasa o dispatch até que a transação complete.

P: Como evitar processamento duplicado para o mesmo evento?

Implementar ShouldBeUnique. Definir uniqueId() para retornar uma chave de cache baseada nos dados do evento. O listener adquire um lock atômico, e dispatches duplicados são pulados se o lock está ativo.

P: Qual é a diferença entre um event listener e um event subscriber?

Um listener trata um tipo de evento. Um subscriber é uma classe que registra handlers para múltiplos eventos relacionados em um único lugar, útil para agrupar eventos de autenticação ou registro de auditoria.

O Que os Eventos do Laravel Significam para Aplicações Escaláveis

  • Eventos desacoplam componentes, permitindo que funcionalidades como notificações e analytics evoluam independentemente
  • Listeners na fila descarregam operações lentas, mantendo as respostas HTTP rápidas
  • ShouldQueueAfterCommit previne condições de corrida entre workers da fila e transações de banco de dados
  • A descoberta automática no Laravel 12 elimina a sobrecarga de configuração, mantendo a lógica dos listeners próxima da implementação
  • Event subscribers consolidam o tratamento de eventos relacionados, reduzindo a dispersão de arquivos para padrões comuns como rastreamento de atividade do usuário
  • O módulo /technologies/laravel/interview-questions/events-listeners no SharpSkill cobre esses padrões com perguntas interativas
Desafio do dia

Você saberia encontrar o bug em Laravel?

Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador da SharpSkill

Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.

Atualizado em 20 de agosto de 2026

Tags

#laravel
#events
#listeners
#php
#event-driven
#queues

Compartilhar

Artigos relacionados