ThinkPHP 表单验证失败时 save() 不会执行,但需显式调用 validate(true) 才生效;直接 data()->save() 不触发验证;require 表示字段必须存在且非空,notempty 检查值是否为空;关联保存需手动传外键;独立 Validate 校验后需手动 $model->error($validate->getError()) 同步错误。

ThinkPHP 表单验证失败时 save() 还会执行吗
不会,但得看你怎么调用。ThinkPHP 的模型 save() 默认不自动触发验证;只有显式调用 validate() 或开启自动验证(如设置 protected $validate = [...] 并启用 validate(true))时,验证失败才会中断保存流程。
常见错误是直接写 $model->data($data)->save(),结果验证形同虚设——数据照存,错误也不报。
- 想让验证生效,必须主动加
validate(true):$model->validate(true)->data($data)->save() - 若用
create()(TP5.0 已废弃,TP6 不再支持),它默认走验证,但已不推荐 - TP6 推荐用
Validate类单独校验,或在模型中定义validateScene配合scene('xxx')
模型里定义验证规则,require 和 must 有什么区别
没有 must 这个验证类型。TP6 的验证规则里只有 require(表示字段必须存在且非空),而 notempty 是检查值是否为空字符串/数组/Null,二者语义不同,容易混用。
比如手机号字段传了空格字符串 " ",require 会通过(因为字段存在),但业务上其实该拒绝。
立即学习“PHP免费学习笔记(深入)”;
-
require:字段必须在数据中出现,且不能是null -
notempty:字段值不能是''、[]、null,但字段本身可选 - 更安全的做法是组合使用:
['mobile', 'require|notempty', '手机号不能为空'] - 正则校验建议用
regex而非check,后者需手写回调,易漏return true/false
验证通过后插入数据库,关联模型的外键没写进去怎么办
验证和关联写入是两件事,ThinkPHP 不会自动把验证通过的数据“透传”给关联操作。如果你用 with() 或 hasOne()->save(),外键字段(比如 user_id)必须显式提供,否则关联模型保存时会因缺失外键而失败或写入 0。
典型现象是主表存进去了,关联表报错 SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value。
- 主模型保存前,先确保数据里有外键字段,例如:
$data['user_id'] = $userId - 用
saveAll()批量保存关联时,每个子数组也得带外键,不能只靠关系定义推断 - 如果用
belongsTo关联,记得在关联定义里指定foreignKey,否则 TP 可能按约定找错字段名 - 调试时可 dump
$model->getLastSql()看实际执行的 INSERT 语句,确认外键是否在 VALUES 里
TP6 中用 Validate 类单独校验,怎么把错误信息塞回模型供模板显示
独立 Validate 实例校验失败后,错误存在 $validate->getError(),但模型本身无感知。模板里用 $model->getError() 是空的,除非你手动赋值。
这不是 bug,是设计使然:验证与模型解耦后,错误传递要自己搭桥。
- 校验后手动绑定:
$model->error($validate->getError()),之后模板中{$model->getError()}就能取到 - 若用
scene分场景,确保Validate实例加载了对应 scene,否则规则不生效 - 注意
batch(true)模式下getError()返回的是数组,模板需遍历,别直接 echo - 别在控制器里用
$this->error()后还继续调save(),逻辑会失控
验证不是开关,是守门人;它拦得住数据,拦不住你绕过它的写法。最容易被忽略的,是验证上下文和模型状态的同步——比如改了数据又没重置模型错误,或者用了 validate 实例却忘了把错误倒灌回去。



















