CodeIgniter 3.x 钩子是静态声明、生命周期固定的插入点系统,需启用 $config['enable_hooks'] = TRUE 并重启服务;钩子点名称须严格匹配内置列表,仅 pre_controller 及之后可安全调用 get_instance();post_controller_constructor 最适合细粒度权限控制。

CodeIgniter 钩子机制不是事件总线,也不是运行时可动态注册的监听器,它是一套静态声明、生命周期固定的插入点系统——只在 CI 3.x 中存在,CI 4 已彻底移除。
钩子必须启用才能生效,否则静默失效
框架不会报错提示你忘了开钩子,$config['enable_hooks'] 默认是 FALSE,这是所有钩子不触发的首要原因。
- 打开
application/config/config.php,确认这行存在且为真:$config['enable_hooks'] = TRUE; - 改完必须重启 Web 服务(如 Apache 或 Nginx),PHP-FPM 缓存可能让配置延迟生效
- CI 4 完全不识别该配置项,若项目已升级,钩子代码会直接被忽略
钩子点名称必须严格匹配 CI 3.x 内置列表
拼写错误、大小写偏差、加空格或自定义名称,都会导致钩子完全不执行,且无任何日志提示。
- 合法钩子点包括:
pre_system、pre_controller、post_controller_constructor、post_controller、display_override、cache_override、post_system - 这些点硬编码在
system/core/CodeIgniter.php中,不可增删或重命名 -
hooks.php中键名必须与之一致,例如写成'Pre_Controller'或'postcontroller'均无效
钩子文件里调用 get_instance() 有严格时机限制
不是所有钩子点都能安全获取 CI 实例,过早调用会直接 fatal error。
-
pre_system和pre_system(注意:文档中偶有笔误重复)中get_instance()不可用——此时CI对象尚未初始化 - 从
pre_controller开始才可调用,此时路由已解析、基础类已加载,能安全访问$this->CI->router、$this->CI->session等 - 若用类方式定义钩子,构造函数内调用
get_instance()必须确保钩子点为pre_controller或之后 - 所有钩子文件头部必须加防护:
defined('BASEPATH') OR exit('No direct script access allowed');
post_controller_constructor 是权限控制最实用的钩子点
它比 pre_controller 更适合做细粒度判断,因为控制器已经实例化,但方法还没执行。
- 此时可通过
$this->CI->router->fetch_class()和$this->CI->router->fetch_method()拿到真实路由目标 - 可结合
$this->CI->session或自定义权限模型做动作级校验 - 避免在
post_controller中做跳转(如redirect()),此时输出缓冲很可能已开启,触发headers already sent - 参数传递靠
params数组,函数签名必须兼容,例如params => ['admin', 'edit']要求函数声明为function check_perm($role = '', $action = '')
钩子机制本质是“切面式注入”,不是松耦合事件;它的灵活性来自预设点的确定性,代价是无法运行时增删。一旦依赖它做关键逻辑(如鉴权),就必须把钩子点选择、get_instance() 可用性、参数对齐这三件事刻进肌肉记忆。


















