codeigniter 3 无真正事件系统,仅支持静态钩子;ci4 才原生支持发布-订阅事件机制。ci3 钩子需手动启用、路径固定、无动态注册,而 ci4 通过 events.php 统一管理监听器并支持自定义事件触发。

CodeIgniter 3 没有真正的“全局事件监听”机制,它只有静态钩子(Hook);而 CodeIgniter 4 才原生支持基于发布-订阅的事件系统。混淆这两者是踩坑的根源。
CI3 中的 hooks.php 不是事件系统,只是生命周期插点
CI3 的 pre_controller、post_system 等钩子点是硬编码在框架执行流里的固定位置,不是运行时可动态注册/触发的事件。它不支持 Events::trigger() 或监听任意自定义事件名。
-
$config['enable_hooks'] = TRUE必须显式开启,否则所有钩子配置静默失效 - 钩子配置只能写在
application/config/hooks.php,且必须返回全局变量$hook - 钩子类中访问 CI 实例必须用
get_instance(),不能直接用$this->session等(因为钩子类不是控制器实例) - 钩子文件路径(
filepath)是相对于APPPATH(即application/),比如'filepath' => 'hooks'对应application/hooks/ - 若钩子文件不存在或不可读,CI 不报错也不记录日志,只跳过——这是调试时最常卡住的地方
CI4 中用 app/Config/Events.php 注册监听器
CI4 的事件系统默认启用,无需开关配置。所有监听逻辑集中在 app/Config/Events.php,通过 Events::on() 绑定回调。
- 监听器可以是匿名函数:
Events::on('pre_system', function() { log_message('info', 'App started'); }); - 也支持类静态方法:
Events::on('post_controller_constructor', [MyAuth::class, 'check']); - 事件名是字符串,可自定义(如
'file_updated'),但需手动调用Events::trigger('file_updated', $data)才会触发 - 多个监听器按注册顺序执行;如需控制优先级,得靠注册先后,CI4 原生不提供数字权重参数
- 监听器内调用
service('someService')可能引发循环依赖——比如该服务初始化时又触发了同名事件
想在 CI3 里模拟事件驱动?别封装太重
有人用单例类 + 回调数组自己实现“事件总线”,但要注意:CI3 生命周期短、无自动 DI 容器,手动管理监听器引用容易内存泄漏或作用域错乱。
- 避免在钩子中 new 一个全局事件对象并长期持有,CI3 请求结束即销毁全部对象
- 如果只是为了解耦“文件更新 → 同步外链表”,用钩子 + 简单函数调用比造轮子更稳:
$this->load->library('file_sync');然后在钩子里调$this->file_sync->update_links($file_id); - 真要跨模块通知,用数据库状态字段 + 定时任务拉取,比强行模拟事件更符合 CI3 的设计哲学
真正容易被忽略的是:CI3 和 CI4 的事件能力根本不在同一抽象层级。拿 CI4 的文档去套 CI3 的 hooks.php,或者反过来以为 CI3 的钩子能响应任意事件名,都会导致逻辑不执行却查不到原因。











