Event Subscribers Instead of Listeners
Event Subscribers Instead of Listeners
~13 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
Besides #[AsEventListener] from chapters 35-36, there's a second way to react to events: event subscribers. Functionally EQUIVALENT, but with a structural difference that matters for MULTIPLE events per class.
The EventSubscriberInterface
<?php
declare(strict_types=1);
namespace App\EventListener;
use App\Event\TaskAssignedEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
class ActivitySubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly LoggerInterface $logger,
) {
}
public static function getSubscribedEvents(): array
{
return [
TaskAssignedEvent::class => 'onTaskAssigned',
'kernel.exception' => 'onException',
];
}
public function onTaskAssigned(TaskAssignedEvent $event): void
{
$this->logger->info('Activity: task assigned.');
}
public function onException(ExceptionEvent $event): void
{
$this->logger->info('Activity: an error occurred.');
}
}getSubscribedEvents() is a STATIC method that CENTRALLY lists WHICH events this class reacts to AND which method handles each one – EXACTLY ONE place to get an overview of the class's entire "area of responsibility".
Listener vs. subscriber: the structural difference
| Approach | Structure |
|---|---|
| #[AsEventListener] (chapters 35-36) | ONE class = ONE event (via the __invoke() parameter's type or the event argument). For TWO events, you need TWO classes OR several separate #[AsEventListener] attributes, each on its own method. |
| EventSubscriberInterface (this chapter) | ONE class can subscribe to SEVERAL events AT ONCE, with differently named methods – the mapping sits CENTRALLY in getSubscribedEvents(). |
Priority with subscribers
public static function getSubscribedEvents(): array
{
return [
TaskAssignedEvent::class => ['onTaskAssigned', 10],
'kernel.exception' => ['onException', -10],
];
}An array [methodName, priority] instead of a single method name – EXACTLY the same priority logic as #[AsEventListener] from chapter 35, just noted in a different place.
Multiple methods for the same event
public static function getSubscribedEvents(): array
{
return [
TaskAssignedEvent::class => [
['log', 10],
['sendNotification', 0],
],
];
}A NESTED array allows several methods for the SAME event, each with its own priority – a case #[AsEventListener] per class CAN'T represent (you'd need several attributes on different methods for that).
Rule of thumb: when a listener, when a subscriber?
Tipp: #[AsEventListener] (chapters 35-36) for the MOST COMMON case: ONE class reacts to ONE event – terser, directly visible on the method. EventSubscriberInterface (this chapter), once ONE class should bundle THEMATICALLY RELATED logic for SEVERAL events (like our ActivitySubscriber, which collects ALL activity logging in ONE place) – both approaches are registered equally (autoconfigure, chapter 34), the choice is purely a structural question.
With that, block 6 (services, dependency injection & events) is almost complete! One last chapter remains: chapter 38 uses EXACTLY the event from this block to actually send an email.