re #97 PSR-14 object-based dispatcher for Altair\Happen#115
Merged
Conversation
Implements PSR-14's object-based interfaces alongside the existing name-keyed EventDispatcher, with no BC break to the name-based surface. A single class cannot satisfy both Altair's dispatch(string, ?EventInterface): EventInterface and PSR-14's dispatch(object): object (same method name, incompatible signatures), so the standardization ships as separate classes (issue's design option 1): - Psr14EventDispatcher implements Psr\EventDispatcher\EventDispatcherInterface: dispatches an event object to its listeners, returns the same instance, and honours StoppableEventInterface (checked before each listener, so an already-stopped event invokes nothing). - Psr14ListenerProvider implements Psr\EventDispatcher\ListenerProviderInterface: type-keyed registration, inheritance/interface-aware matching, deterministic ordering (highest priority first, ties keep registration order via a global sequence counter). getListenersForEvent snapshots+sorts before yielding, so a listener registered mid-dispatch does not fire in the same cycle. Tested: dispatch-by-object, propagation halt, already-stopped short-circuit, priority + FIFO ordering, cross-type merge, inheritance/interface matching, mid-dispatch registration isolation. composer qa + rector dry-run green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements PSR-14's object-based interfaces in
Altair\Happenalongside the existing name-keyedEventDispatcher— no BC break to the name-based dispatch surface. Closes #97 (Phase 3d, AGENT.md §7).Design decision (the reason #97 was its own issue)
The issue offered two shapes. Option 2 (dual-mode, one class) is infeasible: a single class cannot declare a
dispatch()that satisfies both Altair'sdispatch(string $name, ?EventInterface $event): EventInterfaceand PSR-14'sdispatch(object $event): object— same method name, incompatible signatures. So this ships option 1 (separate classes), which is also the cleanest separation: hosts bind whichever dispatcher they need.What's added
Altair\Happen\Psr14EventDispatcher—Psr\EventDispatcher\EventDispatcherInterface. Dispatches an event object to its matching listeners, returns the same instance, and honoursStoppableEventInterface::isPropagationStopped()before each listener (so an already-stopped event invokes nothing, and a listener that stops halts the rest).final readonly.Altair\Happen\Psr14ListenerProvider—Psr\EventDispatcher\ListenerProviderInterface. Type-keyed registration vialisten(class-string $eventType, callable $listener, int $priority); inheritance/interface-aware matching (a listener on a parent class or interface fires for subclasses); deterministic ordering — highest priority first, ties keep registration order via a global sequence counter.getListenersForEvent()snapshots and sorts before yielding, so a listener registered mid-dispatch does not fire in the same cycle.The name-based
EventDispatcher,Event, and all existing contracts are untouched.EventInterfacealready extended PSR-14'sStoppableEventInterface, andcomposer.jsonalready requiredpsr/event-dispatcher.Acceptance criteria
Psr\EventDispatcher\EventDispatcherInterface(dispatch(object): object, returns same instance)Psr\EventDispatcher\ListenerProviderInterfacecomposer qa+rector --dry-rungreenTest plan
[OK] No errorsprocess --dry-run(full tree) —[OK] Rector is done!php-cs-fixer fix --dry-run --using-cache=no— clean