codeigniter 3.x 钩子需显式启用 $config['enable_hooks'] = true 并重启服务,ci 4 已彻底移除;钩子点名称、'function' 和 'filename' 必填、路径相对 apppath;get_instance() 仅在 pre_controller 及之后可用;post_controller_constructor 最适合权限控制,因其可稳定获取路由信息。

CodeIgniter 3.x 的钩子(Hooks)功能必须显式启用,否则所有钩子定义完全不执行;CI 4 已彻底移除该机制,不可复用。
怎么确认钩子开关已真正打开
很多钩子“写好了却没反应”,根源就在这一行配置没生效。不是改了就完事,得确保:
-
$config['enable_hooks']在application/config/config.php中明确设为TRUE(注意是大写 TRUE,不是 true 或 'true') - 修改后必须重启 Web 服务(如 Apache 或 Nginx),PHP-FPM 缓存可能让旧配置继续运行
- CI 4 项目中根本找不到
$config['enable_hooks']这个配置项——它已被删除,强行添加无效
hooks.php 里怎么写一条能触发的钩子规则
钩子点名称拼错、路径写错、必填字段缺失,都会导致静默失败(无报错、无日志、也不执行)。合法定义需同时满足:
- 键名必须是 CI 3.x 预设的钩子点,例如
pre_controller、post_controller_constructor、post_system;pre_system和post_controller也有效,但大小写和下划线不能错 - 数组中
'function'和'filename'两项必须存在;'filepath'是相对于APPPATH(即application/)的目录名,比如写'hooks',不能写'application/hooks/'或'./hooks/' - 如果用了
'class',文件里必须存在同名类,且方法需为 public;类名和函数名不区分大小写,但文件名必须完全匹配(Linux 环境严格区分) - 示例有效写法:
$hook['post_controller_constructor'] = array('class' => 'AuthHook', 'function' => 'check_login', 'filename' => 'AuthHook.php', 'filepath' => 'hooks');
钩子文件里为什么 get_instance() 有时报 Fatal error
get_instance() 不是随时都能调用的——它依赖 CI 核心对象是否已完成初始化。不同钩子点的执行时机差异极大:
- 在
pre_system和pre_system(重复项,实际应为pre_system)中调用get_instance()会直接抛出Fatal error: Call to a member function ... on null,因为此时$CI还未创建 - 从
pre_controller开始,get_instance()才可用;post_controller_constructor更稳妥,此时控制器已实例化,可安全读取$this->CI->router->fetch_class()和$this->CI->router->fetch_method() - 钩子文件开头必须加防护:
defined('BASEPATH') OR exit('No direct script access allowed');,否则被 URL 直接访问会暴露逻辑 - 若用类方式,构造函数中调用
get_instance()是允许的,但仅限pre_controller及之后的钩子点
为什么 post_controller_constructor 比 pre_controller 更适合权限控制
权限判断需要知道“用户正要访问哪个控制器和方法”,而这个信息在 pre_controller 阶段尚未解析完成:
-
pre_controller触发时,路由刚解析完 URI,但控制器类还没 new 出来,$this->CI->router可能返回空或不完整数据 -
post_controller_constructor触发时,控制器对象已实例化,$this->CI->router->fetch_class()和$this->CI->router->fetch_method()能稳定返回当前动作,适合做白名单/角色校验 - 避免在
post_controller中做redirect():此时输出缓冲可能已开启,极易触发headers already sent错误 - 不要试图在钩子里操作数据库日志——
post_system虽然能保证请求结束,但 DB 连接可能已被关闭;真要记日志,优先用log_message()写文件,或在post_controller_constructor中提前注入事务监听逻辑
最易忽略的一点:钩子规则一旦定义,就全局生效,无法按路由或条件动态开关;若需条件性执行,只能在钩子函数内部手动判断 uri_string() 或 $_SERVER['REQUEST_URI'],而不是指望框架帮你过滤。











