timatanga/events

timatanga Events 包

v0.1.4 2021-09-29 17:50 UTC

This package is auto-updated.

Last update: 2024-09-29 06:35:09 UTC


README

将各种应用包聚集在一起需要满足通信需求的基础。因此,事件在解耦包的同时,允许在状态变化时挂钩。

本包深受 Laravel 和 Symfony 的影响。对优秀代码的热爱和对社区的贡献是巨大的。请参阅以下文档以获取更多信息:https://symfony.com.cn/doc/current/components/event_dispatcher.html#events https://laravel.net.cn/docs/8.x/events

为什么不使用那里的组件并提供一个替代组件?我选择这条路径有各种原因

  • Laravel 提供了一个启发灵感的、表达性强的、易于使用的接口。另一方面,对其他包的依赖关系链让我担忧。在构建一个网络应用程序时,我希望没有或至少有最小的依赖关系。也可能某些功能并不需要。
  • Symfony EventDispatcher 组件提供了大量的文档和关于事件使用案例的出色解释。在最小依赖方面,它满足了基础包的预期。另一方面,如果您不经常使用它,界面需要一些脑力劳动。

所以为什么不将这些优势结合在一个简单、轻量级的事件包中。

安装

composer require timatanga/events

分发器

分发器类就像是事件通知系统的脉搏。事件和监听器 创建一个事件分发器实例非常简单

use timatanga\Events\Dispatcher;

$dispatcher = new Dispatcher();

事件分发器支持以下功能

// register one event (as string) or multiple events (as array of strings) for listener
$dispatcher->listen( $events, $listener );

// unregister event listeners
$dispatcher->unlisten( $events, $listener );

// subscribe subscriber implementing EventSubscriberInterface 
$dispatcher->subscribe( $subscriber );

// unregister subscriber
$dispatcher->unsubscribe( $subscriber );

// dispatch event class (payload is then event itself) or event name as string with optional payload argument
$dispatcher->dispatch( $event, $payload );

// check if any listener is registered for event (or all listeners when argument left away )
$dispatcher->hasListeners( $event );

// get event listeners for event (or all listeners when argument left away )
$dispatcher->getListeners( $event );

事件

在应用包之间进行通信时,通常使用事件类进行事件分发。事件类充当相关数据集的容器。根据用例,为任何事件构建事件类可能是一种过度的开销。这两种情况的一个共同点,它们共享事件名称和事件数据。

事件命名

当事件被分发时,它通过一个唯一的名称被识别,可能有任意数量的监听器在监听。唯一的名称可以是任何字符串,但也可以遵循一些命名约定

  • 只使用小写字母、数字、点(.)和下划线(_);
  • 使用命名空间作为前缀,后跟一个点(例如:order.,user.);
  • 以表示已采取动作的动词结束名称(例如:order.placed,order_placed)。

为了确保这些命名约定,事件分发器包括一些检查和转换

  • 对于具有 'name' 属性的事件类,'name' 属性被转换为蛇形写法
  • 对于没有 'name' 属性的事件类,事件名称通过类名(不带命名空间)构建,并转换为蛇形写法,例如:事件类 'User\UserProfileCreated' 转换为事件名称 'user_profile_created'
  • 对于作为字符串注册和分发的事件,应用蛇形写法转换,例如:事件名称 'userProfileCreated' 转换为事件名称 'user_profile_created'

事件有效载荷

无论是作为事件类分发还是以轻量级模式分发,事件都具有传输有效载荷的能力。

事件类分发的有效载荷

// dispatching event class
$dispatcher->dispatch(new Event($subject, [..]))

// event name: 'event'
// event payload: event class itself

请参阅事件类章节以获取有关通用事件类的更多详细信息

轻量级模式的有效载荷

// dispatching simple event
$dispatcher->dispatch('event', [...])

// event name: 'event'
// event payload: [...]

事件类

基本的事件 timatanga\Events\Event 类方便那些希望在应用程序中仅使用一个事件对象的人使用。它可以直接用于大多数目的,因为它遵循标准的观察者模式,其中事件对象封装了一个事件‘主题’,但还增加了可选的额外参数。

__construct($subject, $arguments): Constructor takes the event subject and any arguments;
getSubject(): Get the subject;
setArgument(): Sets an argument by key;
setArguments(): Sets arguments array;
getArgument(): Gets an argument by key;
getArguments(): Getter for all arguments;
hasArgument(): Returns true if the argument key exists;

Event 类实现了 ArrayAccess 和 IteratorAggregate,这使得在事件主题方面传递额外参数变得非常方便。

Event 类实现了 StoppableEventInterface。由于监听器可以访问事件本身,它可以通过使用 $e->stopPropagation() 来停止进一步传播。任何等待处理该事件名称的监听器将不会被事件分发器通知。

监听器

为了利用现有事件,您需要将监听器连接到分发器,以便在事件被分发时进行通知。调用分发器的 listen() 方法将任何有效的 PHP 可调用对象关联到事件。listen() 方法接受最多两个参数

  • 监听器想要监听的事件名称(字符串);
  • 当指定的事件被分发时将被执行的 PHP 可调用对象;

监听器可调用对象

PHP 可调用对象是一个 PHP 变量,它可以由 call_user_func() 函数使用,并在传递给 is_callable() 函数时返回 true。它可以有以下几种情况

  • \Closure 实例;

      $dispatcher->listen('foo', function () use ($a) { ... do something ... }; );
    
  • 实现 invoke() 方法的对象;

      $dispatcher->listen('foo', new CallableClass() { public function __invoke(...$args) { ... do something ... } } );
    
  • 表示函数的字符串或表示对象方法或类方法的数组。

      $dispatcher->listen('foo', [$listener, $method] );
    

通配符监听器

此包提供的事件分发器支持通配符事件,以便更通用的监听器。例如。

  • 注册为 order.created 的监听器仅对此特定事件起作用
  • 注册为 order.* 的监听器将对所有匹配点前缀表示法的事件起作用,如 order.processed、order.closed

订阅者

监听事件最常见的方式是将事件监听器注册到分发器。此监听器可以监听一个或多个事件,并在这些事件被分发时被通知。

另一种监听事件的方式是通过事件订阅者。事件订阅者是一个 PHP 类,能够告诉分发器它应该订阅哪些事件。它实现了 timatanga\Events\Contracts\EventSubscriberInterface 接口,该接口要求一个名为 getSubscribedEvents() 的静态方法。根据订阅者类,分发器解析并注册所有应执行的事件。

class mySubscriber implements EventSubscriberInterface
{
	/*
	 * Only method required by the EventSubscriberInterface
	 */
    public static function getSubscribedEvents()
    {
        return [
            order.created => [ onOrderCreated, onOrderCreatedPost ],
            order.closed => [],
        ];
    }

    public function onOrderCreated( $event )
    {
        // ...
    }

    public function onOrderCreatedPostfix( $event, $dispatcher )
    {
        // ...
    }

分发器在事件被分发时调用注册的方法。分发器允许两个监听器参数

  • 负载:事件类本身或通过 listen 方法注册事件时提供的负载
  • 分发器:分发器实例,以便进行高级用例

自动发现

此包提供的事件发现功能,而不是逐个程序化注册所有事件监听器和事件订阅者。在 config/events.php 文件中,可以添加包含监听器和订阅者的目录以进行自动发现。

return [

    'listeners' => [
        'timatanga/events/tests/Data'
    ],

    'subscribers' => [
        'timatanga/events/tests/Data'
    ],
];

上述配置将搜索 timatanga/events/tests/Data 目录中的事件监听器和订阅者。

事件监听器必须实现 timatanga\Events\Contracts\EventListenerInterface,它强制执行静态 handle 方法以在事件上执行。事件订阅者必须实现 timatanga\Events\Contracts\EventSubscriberInterface,如前几章所述。

在识别实现相应接口的类之后,监听器和订阅者将被注册到事件分发器。如果您想避免自动发现,请创建分发器实例

$dispatcher = new Dispatcher(['autoDiscovery' => false]);