A PSR-14 dispatcher, and the listener I could not order

PSR-14 deliberately says nothing about listener priority, which is a principled decision and occasionally an obstacle.

// the specification: the provider returns listeners in
// an order it chooses. there is no priority argument.

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

// so ordering is the provider's problem, and a provider
// that supports it is not portable.

Two listeners on the same event where one must observe the other’s effect is a design smell rather than an ordering requirement, and that is the specification’s position. Ours was genuine — an audit listener that had to see the final state — and the fix was to make it one listener that does both things, which reads worse and removes the dependency on ordering entirely.