musicode / test

test
14 stars 1 forks source link

[Laravel 模块] Illuminate\Events #18

Open musicode opened 9 years ago

musicode commented 9 years ago

目录结构:

- composer.json
- Dispatcher.php
- EventServiceProvider.php

在 EventServiceProvider 的 register() 中,往 IoC 容器注册了一个 Dispatcher 对象,键名为 events

既然是事件模块,不外乎事件绑定、解绑、触发等逻辑,下面我们来分析 Dispatcher。

我们不妨先把 Dispatcher 的功能列举一下:

监听事件的相关数据会存入 $listeners 数组,它的结构如下:

[
    'event name' => [
        'priority' => [ handler1, handler2, ... ]
    ]
]

可见事件存储分两个维度:priority 和 handler。

事件的优先级体现在触发事件时 handler 的执行顺序,如果按照 $listeners 的数据结构,我们需要做以下事情:

  1. 取出 $listeners[$event] 数组
  2. 按优先级进行排序
  3. 按优先级取出 handler 数组依次执行

每次触发事件都要做这三步有些浪费性能,所以 Laravel 新增了一个 $sorted 属性,用来存放这三步的执行结果。

来看下 sortListeners()

protected function sortListeners($eventName)
{
    $this->sorted[$eventName] = array();
    if (isset($this->listeners[$eventName]))
    {
        krsort($this->listeners[$eventName]);
        $this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]);
    }
}

除了完成前面提到的三步,还把二维数组转成了一维,优先级高的 handler 排在前面,这样便降低了遍历的成本。

通配符监听

如果监听事件名包含 *,便认为是通配符监听。

通配符监听没有优先级的概念,而且它的 handler 是最后执行的。

举个例子,假设监听了两个事件 showshow*,当触发 show 事件时,会先执行 show 的 handler,再执行 show* 的 handler。

事件队列

举个例子,我们给 show 事件注册了一堆 handler,然后我们想触发 show 事件,并给所有 handler 加上一些执行参数,则可以按以下方式调用:

$dispatcher->fire('show', [ 'name' => 'xxx' ]);

这是在触发事件的时候传参,我们也可以在绑定的时候传参,调用方式如下:

$dispatcher->queue('show', [ 'name' => 'xxx' ]);
$dispatcher->flush('show');

这套机制,我始终不懂为何要叫 “事件队列”,但是我也没有更好的名字,暂且就这么用吧...

更多

更多内容,请参考 Laravel 文档