$hidden 属性只能在模型类中静态定义,运行时修改无效;需用 hidden() 或 visible() 方法按接口控制字段,且关联模型需各自定义 $hidden 才能逐层隐藏。

模型的 $hidden 属性只能静态生效,不能动态改;想按权限、场景或接口开关字段,必须在序列化前手动过滤数组,而不是依赖模型定义。
为什么直接改 $hidden 数组没用
PHP 类属性在解析时就固化了,运行时给 $model->hidden = ['password'] 赋值完全无效。ThinkPHP 序列化(toArray()、toJson())读的是类定义里的 protected $hidden = [...],不是实例属性。
- 常见错例:
$user->hidden = ['token']; return $user->toJson();→ token 依然会输出 -
$hidden必须写在模型类里,且字段名要和数据库列名**完全一致**(Linux 下区分大小写,user_id≠userId) - 它只对当前模型原始字段起作用,
with('profile')关联模型里的敏感字段不会被自动隐藏
临时隐藏字段该用 hidden() 还是 visible()
两者都是查询构造器链式方法,但语义和安全性差别很大:
-
hidden(['password'])是黑名单:只删指定字段,漏加一个新字段(比如后来加的last_login_ip)就可能泄露 -
visible(['id', 'name', 'avatar'])是白名单:只返回列出的字段,其余一律丢弃,更安全 - 二者都只影响当前查询结果,不改变模型定义,适合接口级控制
- 注意:
visible()传空数组[]表示“不返回任何字段”,不是“返回全部”
toJson() 还吐出敏感字段?先查这三处
明明设了 $hidden,JSON 里字段还在,大概率是以下任一环节绕过了模型序列化逻辑:
- 调用了
$model->toArray(true)—— 这个true参数强制忽略所有$hidden和$visible规则 - 手动拼数组:
['data' => ['id' => $user->id, 'password' => $user->password]]→ 直接取值,$hidden完全不触发 - 用了
json_encode($model)或第三方 JSON 库 → ThinkPHP 的$hidden只对$model->toJson()生效,不干预原生json_encode
关联模型字段怎么逐层隐藏
$hidden 不会穿透到关联模型,必须每个模型单独定义:
- User 模型里写
protected $hidden = ['token'] - Profile 模型里也得写
protected $hidden = ['id_card'] - Avatar 模型里再写
protected $hidden = ['original_url'] - 如果用
with(['profile.avatar'])预加载,三层的$hidden各自生效,前提是每层返回的都是模型实例(不是数组或原始数据) - 别指望主模型的
$hidden能“传染”给子模型,这是最常被忽略的层级隔离点
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











