mario-legenda/php-event-emitter
从node到PHP的EventEmitter端口
Requires
- php: >=7.0.0
Requires (Dev)
- phpunit/phpunit: ^8.0
This package is auto-updated.
Last update: 2024-09-09 23:21:22 UTC
README
该项目是Node EventEmitter类的轻量级端口。虽然它没有Node EventEmitter的所有功能,但它包含了你立即在类中实现观察者模式所需的所有功能,且代码重构量最小。
安装
支持PHP >7.0
composer require mario-legenda/php-event-emitter
通过扩展EventEmitter类使用
class Task extends EventEmitter
{
public function __construct()
{
parent::__construct(); // don't forget to call the parent Event Emitter constructor
$this->emit('classConstructed');
}
public function runTask(): ExtendedTask
{
$this->emit('preRunEvent');
// some task specific code
$this->emit('postRunEvent');
$this->emit('taskFinished');
return $this;
}
}
$task = new Task();
$task
->runTask()
->on('classConstructed', function($val) {
// called when the classConstructed event is emitted
})
->on('preRunEvent', function($val) {
// called when the preRunEvent event is emitted
})
->on('postRunEvent', function($val) {
// called when the postRunEvent event is emitted
})
->on('taskFinished', function($val) {
// called when the taskFinished event is emitted
})
调用EventEmitter::on()的闭包的替代方案是创建一个实现EventEmitter\CallableInterface的类,该接口暴露一个单一的方法run()
。缺点是在PHP中,我们不能为run()
方法设置可变数量的参数。因此,如果你想使用此接口,你必须将所有期望接收的参数都置为null。例如...
use EventEmitter\CallableInterface;
class Callable implements CallableInterface
{
public function run($argumentOne = null, $argumentTwo = null)
{
}
}
多个事件处理器
可以链式调用多个相同的事件
$eventEmitter = new EventEmitter();
$eventEmitter->emit('event', 'some value');
$eventEmitter
->on('event', function($val) {
// called once
})
->on('event', function($val) {
// called twice
})
->on('event', function($val) {
// called three times
})
在对象中使用
class Task
{
private $eventEmitter;
public function __construct()
{
$this->eventEmitter = new EventEmitter();
}
public function runTask(): ExtendedTask
{
$this->eventEmitter->emit('preRunEvent');
// some task specific code
$this->eventEmitter->emit('postRunEvent');
$this->eventEmitter->emit('taskFinished');
return $this;
}
public function getEventEmitter(): EventEmitter
{
return $this->eventEmitter;
}
}
$task
->runTask()
->getEventEmitter()
->on('classConstructed', function($val) {
// called when the classConstructed event is emitted
})
->on('preRunEvent', function($val) {
// called when the preRunEvent event is emitted
})
->on('postRunEvent', function($val) {
// called when the postRunEvent event is emitted
})
->on('taskFinished', function($val) {
// called when the taskFinished event is emitted
})
如你所见,这两个示例几乎相同。在Task类中创建EventEmitter实例并不是正确的依赖注入,但它使我们能够无缝地使用EventEmitter。客户端代码不知道Task使用的是(或就是)一个EventEmitter。
异常处理
EventEmitter可以处理由你的代码抛出的内部异常。
$eventEmitter = new EventEmitter(true); // notice the argument. That means that exceptions will be handled by EventEmitter
$eventEmitter->emit('event', 'some value');
$eventEmitter
->on('event', function($val) {
throw new \RuntimeException();
})
->exception(function(\Throwable $e) {
// $e instanceof RuntimeException
})
如果你链式调用多个事件,在发生异常的事件之后的所有事件将不会调用。
$eventEmitter
->on('event', function($val) {
throw new \RuntimeException();
})
->on('otherEvent', function($val) {
// this event is never called. Execution passes to the exception()
})
->exception(function(\Throwable $e) {
// $e instanceof RuntimeException
})
API
EventEmitter::__construct($handleErrors = false)
EventEmitter构造函数。如果第一个参数提供true
,则异常将由EventEmitter处理。否则,异常将传递给客户端代码
EventEmitter::emit(string $eventName, ...args): void
注册一个事件,在EventEmitter::on()中调用。必须先调用此方法。
EventEmitter::on(string $eventName, $callback): EventEmitter
执行一个事件。$callback
必须是\Closure
的实例或EventEmitter\CallableInterface
的实例
EventEmitter::exception($callback)
仅当在构造函数中将$handleError
参数设置为true
并且执行一个事件时发生异常时调用
EventEmitter::removeEvent(string $eventName, bool $strictCheck = false): bool
删除一个事件,如果成功则返回true
,失败则返回false
。如果$strictCheck
为true,如果无法删除事件(例如事件不存在),则抛出异常。
EventEmitter::removeAllEvents()
删除所有事件。
EventEmitter::getEventNames(): ?array
返回当前已注册的事件名称数组或null
(如果没有事件)。