在 TP6.0 中进行数据校验时,有不少容易被忽略的细节。例如验证器规则不会自动加载、unique 校验需要显式指定表名、自定义规则返回值类型必须严格匹配——这些看似基础的问题,在实际开发中常常让人“查半天文档才找到原因”。今天就来梳理几个关键要点,帮你避开常见的坑,更高效地完成表单数据验证。

验证器类必须显式加载规则才能生效
许多刚接触 TP6.0 的开发者会误以为,只要在验证器类中定义了 protected $rule,框架就会自动读取并应用。但实际情况并非如此——thinkValidate 实例化后,默认并不会主动加载 $rule 属性,除非你在调用 check() 之前通过构造或链式方式将规则注入进去。换句话说,仅声明属性是不够的,必须在控制器中手动触发加载逻辑。
- 正确做法是:新建一个验证器类(例如
app/validate/UserRegisterValidate.php),继承thinkValidate,并在$rule中写明字段规则。要注意,不能仅靠属性声明就认为规则已注册。 - 调用时必须显式传入数据并执行
check($data),例如validate(UserRegisterValidate::class)->check($data)。 - 如果使用
$this->validate($data, 'UserRegisterValidate')这种写法,控制器需要继承thinkController,并且验证器类的路径必须与命名一致。
Unique 验证必须带表名且注意字段映射
unique 规则在 TP6.0 中并非开箱即用的“智能检测”,它依赖数据库连接和明确的表结构。如果写成 'username' => 'unique',要么直接报错,要么静默失效,无法达到预期的唯一性校验效果。
- 语法格式固定为
unique:表名,字段名,排除ID,额外条件,最简形式是unique:user,username。 - 若要排除当前编辑的记录(例如修改用户时不校验自己),第三个参数填写主键值,比如
unique:user,username,5表示跳过 ID 为 5 的记录。 - 字段名必须与数据库字段完全一致。如果提交的字段是
user_name,但数据库字段是username,必须显式指定:'user_name' => 'unique:user,username'。 - 确保模型或连接配置中已启用对应数据库,并且该表真实存在且可读。
自定义规则函数必须返回 bool 或字符串错误提示
TP6.0 对自定义规则的返回值类型非常敏感:返回 true 表示验证通过,返回 false 或字符串表示失败。如果返回其他类型(如 null、数字、数组),会导致校验中断或抛出异常。这一点在写代码时很容易忽略,但框架不会给出任何提示。
- 函数签名必须为
function($value, $rule, $data, $field),其中$data是整条数据,可用于跨字段判断。 - 例如密码确认规则:
protected function confirmPassword($value, $rule, $data, $field) { return $value === ($data['password'] ?? ''); } - 如果需要带提示语,直接返回字符串,比如
return '两次输入的密码不一致';。此时$message中对应项(如'password.confirmPassword')会被忽略。 - 全局扩展规则(通过
Validate::extend())同样遵循这个返回约定,而且必须在服务启动时注册(例如在app/AppService.php的boot()方法中)。
批量错误收集与场景白名单必须主动开启
默认情况下,TP6.0 验证器遇到第一个错误就停止校验并返回单条提示。如果你希望一次性获取所有错误,或者只校验部分字段,就需要手动控制。
- 启用批量错误:调用
batch(true),例如validate(...)->batch(true)->check($data),返回的是错误数组而非字符串。 - 字段白名单必须用
scene()显式声明,否则$rule全部失效。例如scene('register')对应验证器内的sceneRegister()方法。 sceneRegister()内必须用$this->only([...])列出字段,或用append()加入联动字段(如密码确认),否则confirm_password不会参与校验。- 数组字段校验要用
tags.*语法,例如'tags.*' => 'max:20|regex:/^[a-zA-Z0-9u4e00-u9fa5]+$/',否则规则只作用于整个数组而非每个元素。
实际编写验证器时,最容易被忽略的是 scene 的调用时机和 unique 的表名拼写——少一个字母、多一个空格,都会让唯一性校验形同虚设。因此,每次写完最好仔细检查这些细节,确保验证逻辑准确无误。
