PSR-14 event dispatching, and the interface everyone can implement

Every framework had an event dispatcher and none of them shared an interface, so a library wanting to emit events either picked one or invented its own.

interface EventDispatcherInterface
{
    public function dispatch(object $event);
}

interface ListenerProviderInterface
{
    public function getListenersForEvent(object $event): iterable;
}

interface StoppableEventInterface
{
    public function isPropagationStopped(): bool;
}

The event is any object with no name and no string identifier, which is the decision that makes it typed end to end — listeners match on the class rather than on a string somebody typoed. Separating the dispatcher from the listener provider is what lets a framework keep its own registration mechanism while a library depends only on dispatching. The value is entirely for library authors; an application gains nothing by adopting it directly.