waffle-commons/event-dispatcher
Composer 安装命令:
composer require waffle-commons/event-dispatcher
包简介
Event Dispatcher component for Waffle framework.
README 文档
README
Waffle Event Dispatcher Component
Release:
0.1.0-beta3|CHANGELOG.mdPSR Compliance: PSR-14 (Psr\EventDispatcher\EventDispatcherInterface,ListenerProviderInterface,StoppableEventInterface)
A minimal, attribute-driven PSR-14 dispatcher. The dispatcher itself is final readonly and stateless; the listener provider stores the listener map and supports priority ordering and #[AsEventListener] attribute discovery.
📦 Installation
composer require waffle-commons/event-dispatcher
🧱 Surface
| Class | Role |
|---|---|
Waffle\Commons\EventDispatcher\Dispatcher\EventDispatcher |
final readonly PSR-14 dispatcher. Walks listeners, respects StoppableEventInterface. |
Waffle\Commons\EventDispatcher\Provider\ListenerProvider |
Listener registry. Manual registration via addListener(), or attribute scanning via register($object). |
Waffle\Commons\EventDispatcher\Attribute\AsEventListener |
PHP 8 attribute marking a class or method as a listener. |
Waffle\Commons\EventDispatcher\Event\AbstractStoppableEvent |
Convenience base implementing StoppableEventInterface. |
🚀 Manual registration
use Waffle\Commons\EventDispatcher\Dispatcher\EventDispatcher; use Waffle\Commons\EventDispatcher\Provider\ListenerProvider; $provider = new ListenerProvider(); $provider->addListener(UserRegistered::class, function (UserRegistered $event): void { // … }, priority: 100); // higher priority = earlier $dispatcher = new EventDispatcher($provider); $event = $dispatcher->dispatch(new UserRegistered($userId));
🏷️ Attribute-driven registration (#[AsEventListener])
The attribute is declared as:
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] final readonly class AsEventListener { public function __construct( public ?string $event = null, public int $priority = 0, ) {} }
Method-level — event class resolved from the parameter type-hint
final class AuditListener { #[AsEventListener(priority: 50)] public function onUserRegistered(UserRegistered $event): void { // resolved automatically from the parameter type } } $provider->register(new AuditListener());
Class-level — first public non-constructor method is the handler
#[AsEventListener(event: UserRegistered::class, priority: 50)] final class WelcomeMailer { public function send(UserRegistered $event): void { /* … */ } } $provider->register(new WelcomeMailer());
🛑 Stoppable events
use Waffle\Commons\EventDispatcher\Event\AbstractStoppableEvent; final class CancellableJob extends AbstractStoppableEvent { public function __construct(public readonly string $jobId) {} } $provider->addListener(CancellableJob::class, function (CancellableJob $e): void { if ($shouldCancel) { $e->stopPropagation(); } });
The dispatcher honours isPropagationStopped() and breaks out of the listener loop.
🐘 PHP 8.5 features used
final readonly class EventDispatcher— the dispatcher itself is immutable.- Constructor property promotion with explicit visibility on listeners.
- Typed properties + parameters throughout.
- Inheritance walks via native
get_parent_class()(not reflection caches), so listener resolution against parent event types isO(depth)without warm-up cost.
🧭 Architectural boundary (mago guard)
An active dependency perimeter is enforced on every CI run by vendor/bin/mago guard (bundled into composer mago; zero baselines). The rules live in mago.toml under [guard.perimeter] — a forbidden use statement fails the build, not a reviewer.
Production code under Waffle\Commons\EventDispatcher may depend only on:
Waffle\Commons\EventDispatcher\**— itselfWaffle\Commons\Contracts\**— the shared contracts package, the only Waffle dependency permittedPsr\**— PSR interfaces (PSR-14)@global+Psl\**— PHP core and the PHP Standard Library
Test code under WaffleTests\Commons\EventDispatcher is unrestricted (@all). Structural rules are guarded too: interfaces must be named *Interface, Exception\** classes must end in *Exception, and any Enum\** namespace may hold only enum declarations.
Contract-first, component-agnostic by construction: components compose through waffle-commons/contracts, never directly through one another.
🧪 Testing
docker exec -w /waffle-commons/event-dispatcher waffle-dev composer tests
📄 License
MIT — see LICENSE.md.
统计信息
- 总下载量: 15
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 1
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-05-16