发布于2026-05-23 阅读(0)
扫一扫,手机访问

在ThinkPHP开发中,模型层的$hidden属性常被用来过滤敏感字段,比如密码。但你真的了解它的生效边界吗?一个常见的误解是,只要在模型里设置了$hidden,数据库就查不出这个字段,或者它无论如何都不会泄露。事实并非如此。这个机制有明确的生效范围,用错了场景,敏感数据依然会“大摇大摆”地暴露出来。
首先要明确一点:$hidden是一个“输出过滤器”,而非“查询过滤器”。它不会阻止数据库查询语句去获取password字段。它的工作,仅仅是在模型实例被序列化为数组或JSON时,将指定的键从最终结果里剔除。理解这一点,就能看懂下面几种情况的差异:
User::find(1)->toArray() ✅ 这是$hidden属性的主场,它会生效。User::find(1)->toJson() ✅ 底层通常调用toArray(),因此同样受$hidden控制。json_encode(User::find(1)) ❌ 这行代码直接对模型对象进行序列化,绕过了模型的toArray逻辑,$hidden规则完全失效。User::field('id,password')->find(1)->toArray() ❌ 数据库查询时已经明确查出了password字段,$hidden只是在后续toArray()时选择不显示它,但数据已经被加载到模型属性中了。这可不是真正的“安全”。配置$hidden时,细节决定成败。字段名必须与数据库表的列名严格一致,大小写、下划线都不能错。更重要的是,它的作用范围仅限于当前模型自身的原始字段。
user_id,那么在$hidden数组里就必须写'user_id',写成'userId'或'User_id'都不会生效。User模型里设置了protected $hidden = ['password'],但这管不到它的关联模型。假设User关联了一个Profile模型,Profile里的id_card(身份证号)字段依然会被原样输出。Profile模型内部也单独配置protected $hidden = ['id_card']。append属性添加的虚拟访问器字段(例如_mobile_masked),默认也不受$hidden管理。如果需要隐藏它们,必须显式地将这些虚拟字段名也加入到$hidden数组中。很多开发者遇到“$hidden不生效”的问题,根源在于代码逻辑根本没走到它生效的那一步。下面这些场景,都是典型的“坑”:
立即学习“PHP免费学习笔记(深入)”;
toArray(true) —— 这里的true参数表示强制进行全量导出,它会使得$hidden和$visible(可见字段)的配置全部失效。['id' => $user->id, 'password' => $user->password]这样直接读取对象属性来构造数组,完全绕过了模型的所有输出处理逻辑,$hidden自然不起作用。Db::name('user')->select()返回的是纯粹的数据数组,而不是模型对象实例。既然不经过模型,模型的$hidden属性也就无从谈起了。$user->hidden = ['password']。请注意,$hidden是模型的类属性(protected),而非对象属性。这种运行时赋值通常是无效的。从安全角度出发,相比于用$hidden来“隐藏不想显示的”(黑名单模式),更推荐使用$visible来“指定允许显示的”(白名单模式)。白名单策略更加主动和可控,尤其适用于字段众多、权限要求精细的接口场景。
$hidden配置,转而定义protected $visible = ['id', 'username', 'a vatar']。$user->visible(['id','username'])->toArray()。$visible配置是独立的,不会继承自主模型的设置。$visible设置为空数组[],意味着“一个字段都不返回”,而不是“返回全部字段”。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8