phariscope/event
Composer 安装命令:
composer require phariscope/event
包简介
To implement events in domain driven design or other styles projects with PHP
README 文档
README
composer require phariscope/event
Usage
Steps are:
- Create a domain event (name + past tense verb, example:
AccountCreatedextendsPhariscope\\Event\\Psr14\\Event). - Dispatch this event.
- Distribute events (manually, or enable immediate distribution).
Somewhere else:
- create a listener for an event (example: class
SendEmailWhenAccountCreatedListenerimplementsPhariscope\\Event\\Psr14\\ListenerInterface) - register the listener; when the event is distributed the listener will handle it and do what it has to do
Sample usage in an aggregate constructor
You SHOULD dispatch a domain event from an aggregate to signal its creation. This helps apply the Single Responsibility Principle: cross‑cutting concerns (emails, projections, integrations) live in listeners rather than inside the aggregate.
<?php namespace App\\Domain\\Account; use Phariscope\\Event\\EventDispatcher; use Phariscope\\Event\\Psr14\\Event; use Phariscope\\Event\\Psr14\\ListenerInterface; // 1) The domain event final class AccountCreated extends Event { public function __construct( public string $accountId, \DateTimeImmutable $occurredOn = new \DateTimeImmutable() ) { parent::__construct($occurredOn); } } // 2) The aggregate that emits the event final class Account { public function __construct(private string $id) { // ... domain invariants and state initialization ... // At the end of construction, dispatch the domain event EventDispatcher::instance()->dispatch(new AccountCreated($this->id)); } } // 3) A listener that reacts to the event final class SendWelcomeEmailListener implements ListenerInterface { public function handle(Event $event): bool { if (!$event instanceof AccountCreated) { return false; } // send email here return true; } public function isSubscribedTo(Event $event): bool { return $event instanceof AccountCreated; } } // 4) Wiring the listener and triggering the flow $dispatcher = EventDispatcher::instance(); $dispatcher->subscribe(new SendWelcomeEmailListener()); // Somewhere in your application flow new Account('acc-123'); // Process the queued events (unless you enabled immediate distribution) $dispatcher->distribute();
Immediate distribution
By default, events dispatched via EventDispatcher::dispatch() are queued (FIFO) and processed when you call EventDispatcher::distribute().
If you want events to be processed immediately upon dispatch, enable immediate distribution:
use Phariscope\Event\EventDispatcher; $dispatcher = EventDispatcher::instance(); $dispatcher->distributeImmediately(); // enables automatic distribute() after each dispatch // You can disable it later if needed $dispatcher->disableImmediateDistribution(); // And you can check the current mode if ($dispatcher->isImmediateDistributionEnabled()) { // ... }
Optional logging
You can plug a PSR-3 logger to observe listener exceptions without breaking the dispatch flow:
use Phariscope\Event\EventDispatcher; use Psr\Log\NullLogger; // or Monolog\Logger $dispatcher = EventDispatcher::instance(); $dispatcher->setLogger(new NullLogger());
Deprecated: the misspelled method distributeImmmediatly() is still available for backward compatibility but will be removed in a future release. Use distributeImmediately() instead.
Resetting subscribers (useful in tests)
When using the singleton in tests or long‑running processes, you may need to reset the subscriptions between scenarios:
use Phariscope\Event\EventDispatcher; $dispatcher = EventDispatcher::instance(); // Remove all currently subscribed listeners $dispatcher->clearSubscribers(); // If you also need a fresh instance (clears queue and state) EventDispatcher::tearDown(); $dispatcher = EventDispatcher::instance();
PSR-14 compliance (internal integration)
This package integrates PSR-14 semantics internally while preserving the legacy API:
- You can still use
EventDispatcher(singleton, queue,distribute()/distributeImmediately()). - Listeners remain
Phariscope\Event\Psr14\ListenerInterface. StoppableEventInterfaceis honored: if your event implements it and returnstrueinisPropagationStopped(), the dispatcher stops invoking further listeners after the current one.- Exceptions thrown by listeners are swallowed by the legacy dispatcher (as before). Use the optional PSR-3 logger to observe them.
Complete DDD/TDD Examples
For comprehensive examples showing how to use this library in a Domain-Driven Design context with Test-Driven Development, see DDD-TDD-EXAMPLES.md. This documentation covers:
- Domain Layer: Aggregates, domain events, and event testing
- Application Layer: Services with event distribution and testing
- Infrastructure Layer: Controllers, email listeners, and integration tests
- Complete workflow: From HTTP request to domain event to email notification
- Key practices: Event dispatching, testing with SpyListener, and distribution modes
Migration guide: Legacy API → PSR-14 (concepts)
Mapping
- Legacy dispatcher:
Phariscope\Event\EventDispatcher(queued) → PSR concept: synchronous, immediate dispatch - Legacy listener:
Phariscope\Event\Psr14\ListenerInterface→ PSR concept:callable(object): void - Legacy provider:
Phariscope\Event\ListenerProvider(custom type) → PSR concept: provider returns callables for a given event object - Legacy event type:
Phariscope\Event\Psr14\Event→ PSR concept: anyobject(optionally implementStoppableEventInterface) - Immediate distribution:
distributeImmediately()→ PSR concept: always immediate by design
Steps
-
Install PSR-14 interfaces (already a dependency of this package):
psr/event-dispatcher. -
Instantiate the legacy dispatcher as usual (PSR semantics are handled internally at distribution time).
-
Enregistrer vos listeners legacy via
EventDispatcher::subscribe()comme auparavant. -
Remplacer les appels de distribution:
// Avant (legacy) Phariscope\Event\EventDispatcher::instance()->dispatch($event); Phariscope\Event\EventDispatcher::instance()->distribute(); // Après (sémantique PSR intégrée) $dispatcher->dispatch($event); // synchronously handled when immediate distribution is enabled
-
Propagation stoppable (facultatif): implémentez
Psr\EventDispatcher\StoppableEventInterfaceet retourneztruedansisPropagationStopped()pour arrêter l’enchaînement des listeners. -
Exceptions: sous PSR-14, les exceptions d’un listener ne sont pas avalées. Si votre code dépendait de l’ancienne résilience, entourez l’appel
dispatch()d’untry/catchou adaptez vos listeners.
Event immutability
Events in this library are treated as immutable messages. Listeners MUST NOT modify the event instance they receive. If you need to propagate additional information, dispatch a new event.
To contribute to phariscope/Event
Requirements
- docker
- git
Install
- git clone git@github.com:phariscope/Event.git
Unit test
bin/phpunit
Using Test-Driven Development (TDD) principles (thanks to Kent Beck and others), following good practices (thanks to Uncle Bob and others) and the great book 'DDD in PHP' by C. Buenosvinos, C. Soronellas, K. Akbary
Quality
- phpcs PSR12
- phpstan level 9
- coverage 100%
- infection MSI >99%
Quick check with:
./codecheck
Check coverage with:
bin/phpunit --coverage-html var
and view 'var/index.html' with your browser
Check infection with:
bin/infection
and view 'var/infection.html' with your browser
phariscope/event 适用场景与选型建议
phariscope/event 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 9.14k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2023 年 09 月 24 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「event」 「ddd」 「Domain Driven Design」 「psr-14」 「psr14」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 phariscope/event 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 phariscope/event 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 phariscope/event 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Runn Me! Value Objects Library
Build a domain-oriented application on Laravel Framework
Symfony bundle for broadway/broadway.
Command bus implementation: Commands and domain events
Provides Symfony param converters for mediagone/types-common package.
A module manager for Zend Framework which can be used to create configs per domain.
统计信息
- 总下载量: 9.14k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 20
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2023-09-24