ThinkPHP 6.x模型字段验证须用$rule而非validate(),日期需dateFormat、金额用float+正则,unique要写全表名字段及排除主键,数组校验靠each+tags.*,验证器只判合理、访问器负责格式转换。

ThinkPHP 的数据库字段验证不是“填个 rule 就完事”,它分三层:模型层规则声明、验证器执行逻辑、入库前数据标准化。不厘清这三者的分工,很容易出现“验证通过却插入失败”或“提示模糊用户看不懂”。
模型里写 $rule 还是用 validate()?
ThinkPHP 6.x 中,$rule 是唯一推荐的模型字段验证入口。validate 属性和 validate(true) 调用方式是 5.x 遗留写法,新项目混用会导致规则覆盖、scene 失效或验证跳过。
-
$rule定义在模型类中,自动绑定到模型实例的验证器,支持scene()、batch(true)等全部能力 - 别在模型里同时写
$rule和$validate,后者会被忽略 - 如果用了自定义验证器类(如
UserValidate),就别在模型里再写$rule,否则两套规则打架
日期和金额字段怎么写 rule 才不翻车?
直接写 'create_time' => 'date' 或 'price' => 'number' 是最常见翻车点:前者只认 Y-m-d,传 2024/10/05 就挂;后者允许负数、科学计数法,且不校验小数位数。
- 日期必须显式加
dateFormat:'create_time' => 'date|dateFormat:Y-m-d H:i:s' - 金额别用
number,改用'price' => 'require|float|between:0,99999999.99',再配合正则补精度:^([1-9]\d*\.?\d{0,2}|0\.\d{1,2})$ - 所有规则默认放行空值,必填字段一定要加
require - 验证器只拦错,不转格式 ——
2024/10/05验证通过后仍会以原样入库,MySQL 可能报错。得靠访问器setCreateTimeAttr()统一转成Y-m-d H:i:s
unique 联合唯一和排除自身怎么配?
unique 规则不写全参数,基本等于没写。编辑时重复报错、跨表校验失效、提示信息笼统,八成是这里漏了关键项。
- 联合唯一必须写表名+字段串:
'username,email' => 'unique:user,username,email',字段顺序要和数据库索引一致 - 更新时排除当前记录,得传主键:
'email' => 'unique:user,email^id',^id表示用id字段排除自己 - 如果主键不是
id(比如叫user_id),就得写成email^user_id - 错误提示默认是“该记录已存在”,必须手动配
msg:'msg' => '用户名与邮箱组合已被占用' - 表带前缀(如
tp_user)时,unique里的表名也得带,不然查不到数据
数组字段(如 tags[])怎么逐项校验?
模型默认把 tags[] 当整体,max:5 校的是数组长度,不是每个元素长度。想让每个 tag 都走 max:20,得用 each + tags.* 双规则配合。
-
'tags' => 'require|array|each:alphaNumDash|max:5':确保是数组、非空、最多 5 项、每项只含字母数字和短横线 -
'tags.*' => 'max:20|regex:/^[a-zA-Z0-9\u4e00-\u9fa5]+$/':对每个元素单独限制长度和字符集 -
each:后只能跟字符串规则,闭包必须写在tags.*行里:'tags.*' => function($value) { return !empty(trim($value)); } - 批量错误要完整返回,必须提前调
$validate->batch(true),否则getError()只返回第一条
最易被忽略的是:验证器和访问器的职责边界。验证器负责“这个值合不合理”,访问器负责“这个值存什么格式”。两者不能互相替代,也不能在同一个地方既验证又转换 —— 比如在 setPriceAttr() 里抛异常,会绕过验证流程,前端拿不到标准错误结构。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











