自定义类中无法直接使用 $this->db,因CI自动加载不生效;应通过 service('database')(CI4)或 get_instance()->load->database() 后获取(CI3),并注意环境配置、加载时机及非HTTP场景初始化问题。

自定义类里调用 $this->db 报错 “Undefined property: XXX::$db”
CodeIgniter 的自动加载只对控制器(CI_Controller)、模型(CI_Model)和库(CI_Library)生效,自定义类(比如 app/Helpers/MyService.php 或 app/Services/UserService.php)不继承任何 CI 基类,$this->db 根本不存在。
常见错误现象:在自定义类中直接写 $this->db->query(...),运行时报 Fatal error: Uncaught Error: Cannot access protected property MyService::$db 或类似提示。
- 不要试图让自定义类继承
CI_Controller或CI_Model——这会破坏职责分离,且可能引发生命周期问题(如重复加载、钩子冲突) - 正确做法是通过依赖注入或服务定位器获取数据库实例:CI 4 推荐用
service('database');CI 3 则需手动从 CI 实例中取:get_instance()->db - CI 4 示例:
namespace App\Services; <p>use CodeIgniter\Database\BaseConnection;</p><p>class UserService { protected BaseConnection $db;</p><pre class="brush:php;toolbar:false;">public function __construct() { $this->db = service('database'); } public function find($id) { return $this->db->table('users')->where('id', $id)->get()->getRow(); }}
CI 3 中 get_instance()->db 仍报错“Database not loaded”
即使用了 get_instance(),如果数据库没被加载过,->db 属性还是 null。这不是自动加载失效,而是加载时机问题——get_instance() 返回的是已初始化的 CI 实例,但它的 $db 属性只在第一次调用 $this->load->database() 后才被赋值。
- 必须显式触发一次加载:
get_instance()->load->database(),然后再取get_instance()->db - 更稳妥的做法是封装成懒加载方法:
private function getDB() { $ci =& get_instance(); if (!isset($ci->db) || !is_object($ci->db)) { $ci->load->database(); } return $ci->db; } - 注意:多次调用
$ci->load->database()不会重复连接,CI 3 内部有单例保护
CI 4 自定义类用 service('database') 却连不上,报 “Unable to connect”
这个错误和控制器里报错本质一样,但容易忽略一点:CI 4 的 service('database') 默认读取的是当前环境配置(如 .env 或 app/Config/Database.php),而自定义类可能在 CLI 环境(如命令行任务)下运行,此时 CI_ENVIRONMENT 可能是 production,但 .env 里该环境的数据库配置缺失或错误。
- 先确认当前环境:
echo ENVIRONMENT;(CI 4.4+)或echo CI_ENVIRONMENT; - 检查
.env文件中对应环境段落是否完整,例如:# Development CI_ENVIRONMENT = development database.default.hostname = 127.0.0.1 database.default.username = root database.default.password = database.default.database = myapp_dev
- 若用多数据库配置,
service('database')默认返回default实例;要取其他库,得传参:service('database', 'second_db')
为什么不能把 'database' 加进 $autoload['libraries'] 就完事?
加了也没用。CI 3 的 autoload 是在控制器初始化前执行的,只影响控制器和模型内部的 $this->load 行为;CI 4 的 autoload 更严格,只作用于核心服务注册阶段,不延伸到任意 PHP 类的作用域。
- 自定义类不是框架生命周期的一部分,不会被自动加载机制扫描或注入
- 试图在
autoload.php里写$autoload['libraries'][] = 'database';对自定义类完全无效,只会让控制器变慢(多一次无意义加载) - 真正需要的是“按需获取”,而不是“全局加载”——前者可控,后者易引发连接泄漏或环境错配
最易被忽略的点:CI 4 的 service('database') 在单元测试或非 HTTP 请求场景(如队列任务、定时脚本)中,可能因未初始化 Config 或 Services 类而失败。此时不能只查数据库配置,得先确认 CodeIgniter::boot() 是否已完成,或改用 new \CodeIgniter\Database\MySQLi\Connection(...) 手动构造实例。

















