必须在 config.php 中将 $config['enable_hooks'] = TRUE; 才能启用钩子,否则 hooks.php 无效;CI 4 不支持该机制,仅适用于 CI 3.x。

怎么在 config.php 里打开钩子开关
不启用就完全没用,这是所有钩子执行的前提。很多开发者写了 hooks.php 却没生效,第一反应是钩子写错了,其实只是 $config['enable_hooks'] 还是 FALSE。
- 打开
application/config/config.php - 搜索
enable_hooks,改成$config['enable_hooks'] = TRUE; - 注意:CI 4 不再支持原生钩子机制,这个配置只对 CI 3.x 有效
hooks.php 里怎么写一条合法的钩子规则
钩子定义不是随便写个数组就行,function 和 filename 是必填项,class 可空,但一旦填了就必须匹配文件里的类名,否则报 Call to undefined method。
-
hook_name必须是 CI 预设的点,比如pre_controller、post_controller_constructor,拼错或自定义名称不会触发 -
filepath是相对于APPPATH(即application/)的路径,写成application/hooks/MyHook.php就错,得写hooks - 参数传入靠
params数组,函数签名必须兼容:例如params => ['admin', 'edit'],对应函数就得声明为function check_perm($role = '', $action = '')
示例(检查登录态):
$hook['pre_controller'] = array(
'function' => 'check_login',
'filename' => 'auth_hook.php',
'filepath' => 'hooks'
);
钩子文件里为什么 get_instance() 有时会失效
在 pre_system 或 pre_system 钩子中调用 get_instance() 会直接报错——因为此时 CI 核心对象还没初始化。只有从 pre_controller 开始,get_instance() 才可用。
-
pre_system:不能用get_instance(),也不能加载任何库、模型;适合做环境检测、PHP 版本校验、全局常量定义 -
pre_controller起:CI 实例已存在,可安全调用$this->CI->session、$this->CI->load->model()等 - 如果钩子类用了构造函数,记得加
defined('BASEPATH') OR exit('No direct script access allowed');防止被直接访问
为什么 post_controller_constructor 比 pre_controller 更适合权限控制
因为 pre_controller 触发时控制器都还没实例化,你根本不知道用户要访问哪个方法;而 post_controller_constructor 已完成控制器实例化,能通过 $this->CI->router 拿到当前路由和方法名,做细粒度权限判断才真正可行。
- 获取当前动作:
$this->CI->router->fetch_class()+$this->CI->router->fetch_method() - 别在
post_controller做跳转,此时输出缓冲可能已开启,redirect()会触发 headers already sent 错误 - 若需统一拦截,优先选
post_controller_constructor,它比pre_controller多一个“已知目标”的确定性
filename 写 AuthHook.php,但文件叫 auth_hook.php,Linux 下直接失败;还有人把钩子逻辑塞进控制器构造函数,结果每次都要手动复制,反而失去钩子“解耦”的本意。









