ThinkPHP模型中hidden属性用于静态屏蔽字段,仅作用于当前模型原始字段且区分大小写;visible可反向精确控制返回字段;动态场景应使用withoutField()或field();JSON输出需调用toJson()而非直取data。

ThinkPHP 模型中用 hidden 属性批量屏蔽字段
直接在模型类里定义 hidden 数组,就能让这些字段不随 toArray()、toJson() 或 API 返回时出现。它不是运行时过滤,而是模型层面的静态声明,一设就生效。
常见错误是把字段名写错(比如带表前缀、大小写不一致),或误以为它能屏蔽关联模型字段——其实只作用于当前模型的原始字段。
-
hidden是模型类的 静态属性,必须定义为protected $hidden = ['password', 'salt']; - 字段名必须和数据库列名完全一致(区分大小写,尤其在 Linux 环境下)
- 对
with()关联数据无效;想隐藏关联字段得在关联模型里单独设hidden - 如果用了
append动态属性,hidden对它们也起作用
用 visible 反向控制:只暴露指定字段
当需要返回的字段少、隐藏的字段多时,visible 比 hidden 更安全——它明确列出“允许返回哪些”,其余一律过滤,避免漏加新字段导致敏感信息意外泄露。
典型场景是用户资料接口:只返回 id、nickname、avatar,其他全砍掉,哪怕后续加了 last_login_ip 字段也不会自动透出。
立即学习“PHP免费学习笔记(深入)”;
-
visible和hidden互斥,同时存在时visible优先级更高 - 字段名同样要严格匹配,且不能包含关联字段(如
'profile.real_name'不生效) - 注意:空数组
[]表示“不返回任何字段”,不是“返回全部”
运行时动态隐藏字段(withoutField() 和 field())
如果隐藏逻辑依赖请求参数或业务状态(比如管理员能看到邮箱,普通用户看不到),就得用查询构造器的链式方法,在查库时动态干预,而不是靠模型静态属性。
这时候别碰 hidden,它全局生效、无法按需切换;容易踩的坑是混用 field() 和 hidden,结果字段被双重过滤或冲突失效。
- 用
field(['id', 'name'])显式指定要查的字段(推荐,性能更好) - 用
withoutField('password')临时排除某字段(适合少量字段微调) -
field()传字符串时注意:带逗号的写法如'id,name,avatar'在 ThinkPHP 6.1+ 已废弃,必须传数组 - 这些方法只影响查询 SQL 和结果集字段,不影响模型后续的
save()或验证行为
JSON 输出时字段没隐藏?检查 toJson() 的 options 参数
有时明明设了 hidden,但 toJson() 返回结果里字段还在——大概率是用了自定义 JSON 选项,比如 JSON_UNESCAPED_UNICODE,却忽略了 ThinkPHP 默认会跳过 hidden 处理的底层机制。
ThinkPHP 的 toJson() 内部调用的是 toArray(),所以只要模型字段被 hidden 声明,正常调用就不会出现。但如果手动调用了 json_encode($model->getData()),那就完全绕过了模型的字段过滤逻辑。
- 始终用
$model->toJson()或$model->toArray(),别直取$model->data - 若需自定义 JSON 行为,继承模型并重写
toJson(),但记得先调用parent::toArray() - 调试时可用
dump($model->toArray())看实际输出结构,比看接口响应更准


















