mario-legenda/php-event-emitter

从node到PHP的EventEmitter端口

1.0.3 2019-02-28 18:35 UTC

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(如果没有事件)。