ThinkPHP模型CRUD必须继承think\Model并置于app\model\目录下,类名与表名对应(可配置$table和$pk),查询返回Model实例或Collection,增删改须带where条件,事件验证仅在Model操作中触发。

ThinkPHP 的模型 CRUD 不是直接写 SQL,而是通过模型类封装的链式方法操作数据库,核心在于理解 Db 类和 Model 类的区别——用 Model 才算真正“TP 模型 CURD”,它自带字段验证、事件、自动完成等能力;纯 Db::table() 属于查询构建器,不算模型层。
怎么定义一个可用的模型类
必须继承 think\Model,类名与数据表名默认对应(如 User 模型对应 user 表),且需放在 app\model\ 目录下。不规范命名或路径错误会导致 Class 'app\model\User' not found。
- 文件路径必须是
app\model\User.php - 类名必须是
User,首字母大写,不能写成user或Users - 如果表名不是
user,要在模型里显式指定:protected $table = 'tb_user';
- 主键非
id时,要设置:protected $pk = 'user_id';
查:find()、select()、where() 链式调用要注意什么
模型查询返回的是 think\Model 实例(单条)或 think\Collection(多条),不是原始数组。直接 echo $user->name 可以,但 echo $user['name'] 会报错。
-
find()参数传整数是按主键查,传数组是复合条件(如User::find(['status' => 1])),但更推荐统一用where()->find() -
select()总是返回集合,即使只有一条记录,也不能直接取属性:$users = User::where('status', 1)->select(); echo $users[0]->name; - 字段别名、聚合函数需用
field()显式声明,否则会被自动过滤:User::field('id, name, COUNT(*) as total')->group('status')->select(); - 软删除模型(启用
SoftDeletetrait)默认不查已删除数据,要用withTrashed()或onlyTrashed()
增:save() 和 create() 已废弃,只用 data() + save() 或 create()
TP6+ 中 create() 方法被移除,save() 必须配合 data() 或直接传数组。空模型调用 save() 不会插入数据,必须先赋值。
立即学习“PHP免费学习笔记(深入)”;
- 正确写法(推荐):
$user = new User(); $user->data(['name' => '张三', 'email' => 'z@example.com']); $user->save();
- 或一步到位:
User::create(['name' => '李四', 'email' => 'l@example.com']);
(注意:该方法会触发验证和事件) - 批量插入用
saveAll(),参数是二维数组:User::saveAll([ ['name' => 'A', 'email' => 'a@x'], ['name' => 'B', 'email' => 'b@x'] ]); - 如果模型设置了
$autoWriteTimestamp = true,create_time和update_time字段会自动写入,无需手动传
删和改:where() 不写会全表操作,非常危险
delete() 和 save() 都依赖前置的 where() 条件,漏写等于清空或更新整张表。TP 不做“无 where 保护”,线上环境务必加日志或调试开关校验 SQL。
- 安全删除示例:
User::where('id', 123)->delete(); // 删除单条 - 更新必须带条件:
User::where('id', 123)->save(['status' => 2]); - 自增/自减用
inc()/dec():User::where('id', 123)->inc('score', 10)->update(); - 软删除不是
delete(),而是delete(true)或直接调用trash()(如果模型用了 SoftDelete)
最易被忽略的是模型事件和验证的触发时机:只有通过 Model 实例的 save()、create()、update() 才会触发 before_insert 等事件;用 Db::name('user')->where(...)->update(...) 完全绕过模型层,字段自动处理、事件、验证全部失效。











