ThinkPHP 6 的 validateScene 不校验嵌套数组是设计使然,因其默认以点号分隔字段,而表单嵌套使用方括号语法;需改用 validate 方法并显式传入完整数据,规则中字段名须严格匹配如 'user[profile][age]',且 scene 中须显式声明该字段。

ThinkPHP 6 的 validateScene 不校验嵌套数组?
默认场景验证只处理一级字段,validateScene 对 user[profile][age] 这类嵌套键名直接忽略——不是 bug,是设计如此。ThinkPHP 的验证器默认把点号(.)当分隔符,但表单提交的嵌套数组实际用的是方括号语法,两者不自动对齐。
实操建议:
- 改用
validate方法并显式传入完整数据,而非依赖validateScene自动提取 - 在控制器里先用
input()拿到原始数据,再调用验证器:$this->validate($this->request->input(), 'rule') - 验证规则里必须用方括号写法:
'user[profile][age]' => 'require|number|between:1,120',不能写成user.profile.age
嵌套数组规则怎么写才生效(以 TP6.1 为例)
ThinkPHP 验证器对嵌套结构的支持依赖字段名完全匹配,且需配合 scene 中显式声明该字段,否则即使规则写了也跳过校验。
常见错误现象:提交 { "user": { "profile": { "age": "" } } },但验证没报错。
立即学习“PHP免费学习笔记(深入)”;
实操建议:
- 规则文件中字段名严格对应 POST 键名:
'user[profile][age]',包括中括号和顺序 - 若用
scene,必须在scene数组里加入该完整字段:'edit' => ['user[profile][age]', 'user[name]'] - 嵌套层级深时,推荐用
each验证数组项:'tags.*' => 'require|max:20',注意*是通配符,不是正则
Validate::make 动态验证嵌套数据时的坑
用 Validate::make 手动构建验证器时,容易漏掉数据预处理——比如前端传的是 JSON 字符串,后端没 json_decode 就直接丢给验证器,会导致所有嵌套字段被当成字符串校验失败。
使用场景:API 接口接收 application/json 请求体,含多层对象。
实操建议:
- 先判断请求类型:
if ($this->request->isJson()) { $data = $this->request->param(); },TP6 的param()会自动解析 JSON - 避免手动
json_decode($raw, true)后再传,可能破坏原始键名结构(如数字键变整型) - 验证前用
dump($data)确认结构是否符合预期,特别是空数组、null 值是否被转成空字符串
自定义验证规则处理对象嵌套(如校验用户权限树)
标准规则无法表达“每个子节点的 pid 必须存在于父级列表中”这类跨字段逻辑,必须写自定义方法。
性能影响:每层递归都查数据库会拖慢响应,尤其嵌套深、节点多时。
实操建议:
- 在验证器类中定义方法:
protected function checkPermissionTree($value, $rule, $data),$data是全部输入,可安全取$data['nodes'] - 提前把所有
id提出来做array_flip建索引数组,别在循环里反复in_array - 规则写法:
'nodes' => 'checkPermissionTree',不要带括号或参数,传参靠$data
dump($this->request->param()) 看一眼原始输入长什么样。



















