CodeIgniter钩子机制需三步生效:一、在config.php中设$config['enable_hooks'] = TRUE;二、在hooks.php中按预设钩子点(如pre_controller)定义数组;三、钩子文件置于application/下对应路径,通过get_instance()获取CI实例(pre_system除外)。

CodeIgniter 没有原生的 dispatch_event() 或事件总线,所谓“事件触发器”实际就是它的钩子(Hook)机制——静态配置、生命周期固定、不支持运行时订阅。想靠它实现类似 Laravel 的事件系统?行不通;但用来做权限检查、日志埋点、输出拦截?够用,且轻量。
怎么让钩子真正生效:三步缺一不可
钩子默认是关闭的,开了配置还不算完,漏掉任意一步都会静默失效:
-
$config['enable_hooks'] = TRUE必须在application/config/config.php中显式设为TRUE;默认是FALSE,框架不会报错也不会提醒 - 钩子定义必须写在
application/config/hooks.php,且文件必须以<?php开头,包含defined('BASEPATH') OR exit('No direct script access allowed'); -
$hook数组必须存在并返回,不能是空数组或未定义变量;写成$hooks或$HOOK都会失效
pre_controller 和 post_controller 的典型误用场景
这两个钩子点最常用,也最容易用错时机:
-
pre_controller触发时,控制器类尚未实例化,$this不可用;适合做全局前置校验(如登录态检查),但不能调用$this->session——得用get_instance()->session -
post_controller在控制器方法执行完、视图尚未渲染前触发;此时$this可用,但$this->output->get_output()还拿不到最终 HTML(要等display_override) - 想修改响应内容?别用
post_controller,它不接管输出流;改用display_override,并在里面手动调用echo $this->output->get_output()再处理
钩子类里怎么安全访问 CI 核心对象
钩子文件加载时,CI 实例尚未注入到类中,直接写 $this->db 会报错:
- 必须用
$CI =& get_instance()获取当前 CI 实例引用,这是唯一可靠方式 - 不要在构造函数里提前调用
get_instance(),某些钩子点(如pre_system)此时 CI 尚未初始化,会返回NULL - 如果钩子逻辑需要数据库操作,优先放在
post_controller或更晚的钩子点;pre_system里连$CI->load都不可用 - 示例写法:
public function check_login() { $CI =& get_instance(); if (!$CI->session->has_userdata('user_id')) { redirect('login'); } }
钩子路径和文件加载失败为什么没报错
钩子配置里 filepath 是相对于 APPPATH(即 application/)的,不是项目根目录:
-
'filepath' => 'hooks'→ 实际找的是application/hooks/AuthHook.php - 文件不存在、权限不足、PHP 语法错误,CI 全部静默跳过,不记录日志也不抛异常
- 调试时建议加一行日志:
log_message('debug', 'AuthHook loaded');放在钩子方法开头,确认是否真的执行了 - 别把钩子类放进
libraries/或core/目录下——框架只认filepath指定的路径,其他位置一概不加载
Events::trigger())。但对老项目做小范围增强,钩子仍是最低成本的选择。


















