Event Subscriber statt Listener
Event Subscriber statt Listener
~13 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Neben #[AsEventListener] aus den Kapiteln 35-36 gibt es einen zweiten Weg, auf Events zu reagieren: Event Subscriber. Funktional GLEICHWERTIG, aber mit einem strukturellen Unterschied, der bei MEHREREN Events pro Klasse relevant wird.
Das EventSubscriberInterface
<?php
declare(strict_types=1);
namespace App\EventListener;
use App\Event\AufgabeZugewiesenEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
class AktivitaetsSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly LoggerInterface $logger,
) {
}
public static function getSubscribedEvents(): array
{
return [
AufgabeZugewiesenEvent::class => 'onAufgabeZugewiesen',
'kernel.exception' => 'onException',
];
}
public function onAufgabeZugewiesen(AufgabeZugewiesenEvent $event): void
{
$this->logger->info('Aktivität: Aufgabe zugewiesen.');
}
public function onException(ExceptionEvent $event): void
{
$this->logger->info('Aktivität: Fehler aufgetreten.');
}
}getSubscribedEvents() ist eine STATISCHE Methode, die ZENTRAL auflistet, auf WELCHE Events diese Klasse reagiert UND welche Methode dafür jeweils zuständig ist – GENAU EIN Ort, um den gesamten "Zuständigkeitsbereich" der Klasse zu überblicken.
Listener vs. Subscriber: der strukturelle Unterschied
| Ansatz | Struktur |
|---|---|
| #[AsEventListener] (Kapitel 35-36) | EINE Klasse = EIN Event (über den Typ des __invoke()-Parameters oder das event-Argument). Für ZWEI Events braucht man ZWEI Klassen ODER mehrere separate #[AsEventListener]-Attribute mit jeweils eigener Methode. |
| EventSubscriberInterface (dieses Kapitel) | EINE Klasse kann MEHRERE Events auf EINMAL abonnieren, mit unterschiedlich benannten Methoden – die Zuordnung steht ZENTRAL in getSubscribedEvents(). |
Priorität bei Subscribern
public static function getSubscribedEvents(): array
{
return [
AufgabeZugewiesenEvent::class => ['onAufgabeZugewiesen', 10],
'kernel.exception' => ['onException', -10],
];
}Statt eines einzelnen Methodennamens ein Array [Methodenname, Priorität] – GENAU dieselbe Priorität-Logik wie bei #[AsEventListener] aus Kapitel 35, nur an anderer Stelle notiert.
Mehrere Methoden für dasselbe Event
public static function getSubscribedEvents(): array
{
return [
AufgabeZugewiesenEvent::class => [
['protokolliere', 10],
['sendeBenachrichtigung', 0],
],
];
}Ein VERSCHACHTELTES Array ermöglicht mehrere Methoden für DASSELBE Event, jeweils mit eigener Priorität – ein Fall, den #[AsEventListener] pro Klasse NICHT abbilden kann (dort bräuchte man dafür mehrere Attribute auf verschiedenen Methoden).
Faustregel: wann Listener, wann Subscriber?
Tipp: #[AsEventListener] (Kapitel 35-36) für den HÄUFIGSTEN Fall: EINE Klasse reagiert auf EIN Event – knapper, direkt an der Methode sichtbar. EventSubscriberInterface (dieses Kapitel), sobald EINE Klasse THEMATISCH ZUSAMMENGEHÖRENDE Logik für MEHRERE Events bündeln soll (wie unser AktivitaetsSubscriber, der ALLE Aktivitäts-Protokollierung an EINEM Ort sammelt) – beide Ansätze sind gleichwertig registriert (Autoconfigure, Kapitel 34), die Wahl ist eine reine Strukturfrage.
Damit ist Block 6 (Services, Dependency Injection & Events) fast abgeschlossen! Ein letztes Kapitel fehlt noch: Kapitel 38 nutzt GENAU das Event aus diesem Block, um tatsächlich eine E-Mail zu versenden.