事件

CodeIgniter 事件特性提供了一种方法来修改框架的内部运作流程或功能,而无需修改核心文件的能力。CodeIgniter 遵循着一个特定的流程来 运行。但是,在某些情况下,你可能想在执行特定流程时执行某些特定的操作。例如在加载控制器之前或之后立即运行一个特定的脚本。或者在其他的 某些位置触发你的脚本。

事件已发布/订阅模式工作,可以在脚本执行过程中的某个时刻触发事件。其他脚本可以通过向 Events 类来注册订阅事件,使它知道在脚本触发事件 时该执行什么操作。

启用事件

事件始终处于启用状态,并且全局可用。

定义事件

大多数的事件都定义在 app/Config/Events.php 文件中。不过你也可以通过 Events 类的 on() 方法定义事件。第一个参数是事件 名称,第二个参数是当触发该事件时执行的操作:

use CodeIgniter\Events\Events;

Events::on('pre_system', ['MyClass', 'MyFunction']);

在这个例子中,任何时候触发 pre_controller 事件,都会创建 MyClass 实例并运行 MyFunction 方法。

第二个参数可以是 PHP 能识别的任何 可调用结构:

// 调用 some_function 方法
Events::on('pre_system', 'some_function');

// 调用实例方法
$user = new User();
Events::on('pre_system', [$user, 'some_method']);

// 调用静态方法
Events::on('pre_system', 'SomeClass::someMethod');

// 使用闭包形式
Events::on('pre_system', function(...$params)
{
        . . .
});

设置执行优先顺序

由于可以将多个方法订阅到一个事件中,因此需要一种方式来定义这些方法的调用顺序。你可以通过传递优先级作为 on() 方法的第三个参数来实现。 事件系统将优先执行优先级较低的值,优先级最高的值为 1:

Events::on('post_controller_constructor', 'some_function', 25);

如果出现相同优先级的情况,那么事件系统将按定义的顺序执行。

注解

可以理解为事件系统会根据事件名称分组排序,按第三个参数升序排列,然后依次执行。

Codeigniter 内置了三个常量供您使用,仅供参考。你也可以不使用它,但你会发现他们有助于提高可读性:

define('EVENT_PRIORITY_LOW', 200);
define('EVENT_PRIORITY_NORMAL', 100);
define('EVENT_PRIORITY_HIGH', 10);

排序后,将按顺序执行所有订阅者。如果任意订阅者返回了布尔类型 false,订阅者将停止执行。

发布自定义的事件

使用事件系统,你可以轻松创建自己的事件。要使用此功能,只需要调用 Events 类的 trigger() 方法即可:

\CodeIgniter\Events\Events::trigger('some_event');

当然,你也可以为订阅者传递任意数量的参数,订阅者将会按相同的顺序接收参数:

\CodeIgniter\Events\Events::trigger('some_events', $foo, $bar, $baz);

Events::on('some_event', function($foo, $bar, $baz) {
        ...
});

模拟事件

在测试期间,你可能不希望事件被真正的触发,因为每天发送数百封电子邮件记缓慢又适得其反。你可以告诉 Events 类使用 simulate() 方法 模拟运行事件。如果为 true,那么将跳过所有事件,不过其他的内容都会正常运行:

Events::simulate(true);

你也可以传递 false 停止模拟:

Events::simulate(false);

事件触发点

以下是 Codeigniter 核心代码中可用的事件触发点列表:

  • pre_system 系统执行过程中最早被调用。此时,只有 基准测试类 和 钩子类 被加载了, 还没有执行到路由或其他的流程。
  • post_controller_constructor 在你的控制器实例化之后立即执行,控制器的任何方法都还未调用。
  • post_system 最终数据发送到浏览器之后,系统执行结束时调用。