ci3 默认不支持子目录控制器作默认控制器,需通过routes.php配置路由规则(如$route['admin/(:any)'] = 'admin/$1')并规范类名、文件名大小写;加载模型和视图须显式指定子目录路径;多级子目录需扩展my_router类重写_validate_request()方法。

CI3 默认不支持子目录控制器作为默认控制器
直接在 $route['default_controller'] = 'front/home'; 会 404,因为 CI3 的 _set_default_controller() 方法只拆分一次 /,把 front/home 当成「类名 front,方法名 home」,然后去 controllers/front.php 找文件——但实际路径是 controllers/front/Home.php。根源在 system/core/Router.php 中那段硬编码逻辑。
启用子目录路由需两步:改路由配置 + 显式声明子目录规则
不用动核心文件,靠 routes.php 就能安全支持子目录访问(如 /admin/user、/api/v1/order):
-
$route['admin/(:any)'] = 'admin/$1';—— 匹配所有/admin/xxx并转发到application/controllers/admin/下对应控制器 -
$route['api/v1/(:any)'] = 'api/v1/$1';—— 同理,注意路径层级必须与物理目录严格一致(大小写敏感) - 确保控制器类名首字母大写,文件名也大写,例如
application/controllers/admin/User.php内必须是class User extends CI_Controller - 不要漏掉
$route['admin'] = 'admin';这类单级入口,否则/admin会 404
子目录控制器里调用模型和视图的路径要手动对齐
CI 不自动推导子目录下的关联路径,$this->load->model('User_model') 仍去根目录找;视图也默认从 views/ 开始解析,不会进 views/admin/:
- 加载模型要带子目录前缀:
$this->load->model('admin/User_model');(前提是该模型放在models/admin/User_model.php) - 加载视图必须写全路径:
$this->load->view('admin/user/list');对应views/admin/user/list.php - 如果多个子目录共用同一组模型(如
User_auth_model),建议统一放在models/core/并用$this->load->model('core/User_auth_model');
多级子目录(如 controllers/api/v1/user)要自定义 Router 类
CI3 原生只支持一级子目录(admin/User),二级及以上(api/v1/User)会报错或跳转失败。此时必须扩展 Router:
- 新建
application/libraries/MY_Router.php,继承CI_Router,重写_validate_request() - 核心逻辑是遍历 URI 段,逐层判断是否为目录,动态拼接
$this->directory - 别忘了在
routes.php中补上$route['api/v1/(:any)'] = 'api/v1/$1';,否则自定义 Router 不会被触发 - 这个方案绕过了修改
system/目录的风险,但每次升级 CI 都要验证MY_Router兼容性
子目录管理真正难的不是路由通不通,而是模型职责边界和视图路径一致性——一旦控制器进了 admin/,它就不该再混用 front/ 的服务逻辑,否则模块化就只剩目录空壳了。











