ThinkPHP中控制器与模型交互本质是“请求驱动+职责分离”:控制器接收请求并调用模型,模型专注数据验证、处理与存取;控制器通过实例化、静态方法或依赖注入调用模型,模型通过验证、过滤、钩子响应指令,错误由控制器统一处理;跳过模型直写SQL会导致重复代码、验证失控和维护困难。

ThinkPHP 中控制器与模型的交互,本质是“请求驱动 + 职责分离”的协作过程:控制器接收并解析用户请求,决定调用哪个模型、执行什么操作;模型专注数据层行为——验证、处理、存取,不关心 HTTP、路由或页面渲染。
控制器怎么调用模型
控制器通过实例化模型类或静态方法触发数据操作,常见方式有三种:
-
实例化调用:使用
D('User')(TP3.x)或new User()/User::create()(TP6+),适合需复用对象或自定义初始化逻辑的场景 -
静态快捷调用:如
User::where('status', 1)->select(),简洁直接,适用于简单查询或单次操作 - 依赖注入调用(TP6 推荐):在控制器构造函数或方法参数中声明模型类型,框架自动注入,利于测试和解耦
模型如何响应控制器的指令
模型不是被动容器,它主动承担数据规则与流程控制:
-
自动验证:控制器调用
create()或validate()时,模型依据$_validate(TP3)或验证器类(TP6)校验字段,失败则返回 false 并设$this->error -
自动过滤:通过
$_filter(TP3)或验证器的filter选项,对输入值做 trim、htmlspecialchars 等预处理 -
钩子方法干预:如
_before_insert(TP3)或beforeWrite(TP6),可在数据写入前修改字段(例如生成缩略图、设置时间戳、加密密码)
数据流向与错误传递机制
控制器不直接操作数据库,所有数据变更必须经由模型完成;模型也不直接输出错误给前端,而是将状态反馈给控制器统一处理:
立即学习“PHP免费学习笔记(深入)”;
- 成功时,模型返回主键 ID(新增)、影响行数(更新/删除)或数据对象/集合(查询)
- 失败时,模型内部设置
$this->error(TP3)或抛出ValidateException(TP6),控制器通过$model->getError()或 try-catch 捕获并调用$this->error()响应用户 - 文件上传、图片处理等非数据库操作,也应在模型的钩子中完成,确保业务逻辑集中,控制器保持轻量
为什么不能跳过模型直接在控制器里写 SQL
看似省事,实则埋下三类隐患:
- 重复代码:同一张表的增删查改逻辑散落在多个控制器中,改一个字段要全局搜索替换
- 验证失控:SQL 执行前无统一校验,容易插入非法数据(如超长用户名、负价格),后续排查成本高
- 维护困难:数据库结构变更(如字段重命名、加索引)需同步修改所有 SQL,而模型只需改一处属性或验证规则



















