thinkphp 6.1+ 验证器 scene 方法需配合 only/except 或显式声明 $scene 才生效;rule 中闭包须注册为自定义规则才能使用;geterror() 为空可能因未调用 check、缺错误提示或 batch 模式影响;unique 规则需注意表名字段名大小写及跨库限制。

验证器类里 scene 方法失效了?检查是否漏了 only 或 except
ThinkPHP 6.1+ 把验证场景逻辑从“自动匹配”改成了显式声明,scene 方法本身没删,但只负责定义规则集,不触发校验。真正执行时必须配合 only 或 except 才会按场景过滤字段。
- 常见错误现象:
$validate->scene('edit')->check($data)返回true,但实际没校验edit场景里定义的字段,因为没加only() - 正确写法是:
$validate->scene('edit')->only(['username', 'email'])->check($data),或者直接用scene('edit')->check($data)(前提是验证器类中已通过protected $scene = [...]显式声明过该场景包含哪些字段) - 升级后容易忽略的一点:旧项目迁移时,如果原来靠
scene自动推导字段,现在必须补全$scene数组,否则scene('xxx')调用等于白做
rule 数组里写闭包函数,为什么校验总不触发?
ThinkPHP 验证器的 rule 支持闭包,但仅限于「内置规则扩展」场景,不是随便放个 function() 就能当校验逻辑用。闭包必须返回布尔值,且不能依赖外部变量(比如没 use 的 $this),否则运行时报错或静默跳过。
- 常见错误现象:在
rule里写['password' => function($value) { return strlen($value) > 8; }],结果这个规则完全没生效,也不报错 - 根本原因:验证器默认只识别字符串规则名(如
'require|alphaNum'),闭包必须注册为自定义规则,再通过字符串引用,例如先调用Validate::extend('strong_pwd', function($value) {...}),然后 rule 里写'password' => 'strong_pwd' - 替代方案更简单:直接在验证器类里重写
check方法,或用filter+after钩子处理复杂逻辑,比硬塞闭包到rule更可控
验证失败时 $validate->getError() 返回空?定位三个关键点
不是所有失败都会进 getError(),它只返回最后一条(或全部,取决于配置),而且前提是验证器确实执行了校验、且有规则明确抛出错误信息。
- 检查是否调用了
check()—— 有些代码误以为赋值就触发校验,其实只是设置数据,必须显式调用 - 确认规则里写了错误提示,比如
'required' => ':attribute 不能为空',如果只写'required'没配 message,getError()可能为空或返回默认中文(取决于语言包加载状态) - 注意
batch模式影响:开启batch(true)后,getError()返回数组,不是字符串;而默认单条模式下,它只取第一个字段的第一个错误,其余被丢弃
数据库唯一性验证 unique 规则查不到数据?小心表名和字段名大小写
unique 规则是基于 Db 查询构建的,ThinkPHP 默认不会帮你转义表名或字段名,遇到 MySQL 严格模式或 PostgreSQL 时,大小写敏感会导致查不到记录。
- 典型问题:验证器里写
'email' => 'unique:users,email',但数据库表实际叫Users(大写 U),MySQL 在某些配置下会查不到 - 解决方法:统一用小写表名,或显式指定完整表名+别名,例如
'unique:think_users,email,id^123',其中id^123表示排除主键为 123 的记录(用于编辑时绕过自身) - 另一个坑:
unique不支持跨库查询,如果用户表在auth库而当前连接是main,得手动写callback规则 +Db::connect('auth')查
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











