codeigniter本身不提供orm,new user()报$db为null是因为绕过ci加载机制,$this->db由ci_loader在生命周期中注入;需通过get_instance()或手动load database获取实例。

CodeIgniter 本身不提供 ORM,所谓“在 CodeIgniter 中使用 ORM”,实际是引入第三方库或自行封装——直接调用 new User() 会报 Call to a member function query() on null 或类似错误,根本原因是 CI 的数据库连接未被初始化。
为什么 new User() 会触发 $this->db 未定义?
CI 的 $this->db 是通过 CI_Loader 在控制器/模型生命周期中注入的。而 new User() 是纯 PHP 实例化,完全绕过 CI 加载机制,导致构造函数里访问 $this->db 时为 null。
- 所有自定义类(如
User)若需数据库能力,必须显式传入或获取 CI 实例,例如get_instance() - 不能在
__construct()中直接调用$this->db->...,除非你手动调用$this->load->database()并确保上下文正确 - 常见错误堆栈起点往往是
system/database/db_driver.php第 1 行,本质是方法调用链上某个对象为null
用 Doctrine ORM 替代原生 Query Builder 的关键步骤
Doctrine 是目前与 CodeIgniter 集成最稳定、文档最全的 ORM 方案,它不依赖 CI 生命周期,而是通过 Composer 独立管理实例。
- 先执行
composer require doctrine/orm,再手动配置EntityManager实例(通常放在application/core/MY_Loader.php或独立服务类中) - 实体类必须用 PHPDoc 注解或 YAML/XML 定义映射,例如
@Entity @Table(name="users"),不能靠约定自动识别 - 查询不再走
$this->db->get(),而是用$em->getRepository(User::class)->findAll() - 注意事务控制:CI 的
$this->db->trans_start()对 Doctrine 无效,必须用$em->beginTransaction()
用 datamapper-ci 这类轻量级扩展的风险点
datamapper-ci 是早期为 CI 2.x 设计的 DataMapper 实现,虽简单,但与 CI 3.x+ 兼容性差,且已多年未维护。
- 它要求模型类继承
DataMapper基类,并在构造时强制加载数据库,容易与 CI 3.x 的CI_Model初始化顺序冲突 - 关系定义(
$has_many、$has_one)依赖魔术属性,PHP 8+ 下可能触发Deprecated: Accessing static property警告 - 不支持复合主键、JSON 字段、软删除等现代需求,出问题时调试困难,因为错误常被封装在基类内部
不引入 ORM 时,怎么写出接近 ORM 的代码风格?
如果你只是想让模型更“对象化”,又不想引入复杂依赖,可以基于 CI 原生 CI_Model 封装一层轻量逻辑:
- 在模型中定义
public $table = 'users',并在__construct()里调用$this->load->database() - 用
protected function _insert($data)统一封装写入逻辑,避免控制器里拼array('name' => $name) - 把字段名转成属性访问(如
$user->name)需配合__get()/__set(),但要注意性能损耗和 IDE 不识别的问题 - 慎用自动填充:CI 的
$this->user_model->created_at = date('Y-m-d H:i:s')看似方便,实则破坏数据一致性边界
真正卡住人的从来不是“能不能用 ORM”,而是没意识到 CI 的加载机制和对象生命周期是硬约束——ORM 不是插件,是另一套数据访问范式,混用时边界必须划清。











