Entity::toArray() 默认导出所有字段,需通过重写 _hidden 属性或 toArray() 的 hidden 选项排除敏感字段;_hidden 仅影响序列化输出,不作用于数据库操作,且不支持通配符;动态控制需用 hidden 参数,会完全覆盖 _hidden;未声明为 _accessible 或 _virtual 的字段不会被导出。

Entity::toArray() 默认导出所有字段,如何排除敏感字段?
默认调用 toArray() 会把实体所有属性(包括数据库字段、虚拟字段、临时属性)一股脑转成数组。如果你有 password_hash、api_token 或 is_deleted 这类不该暴露的字段,必须主动过滤。
最直接的方式是在实体类中重写 _hidden 属性:
class User extends Entity
{
protected $_hidden = ['password_hash', 'api_token', 'remember_token'];
}
这个数组只影响 toArray() 和 JSON 序列化(如 json_encode($entity)),不影响数据库操作或内部属性访问。
-
_hidden是硬过滤:字段值不会出现在输出里,哪怕它实际存在且非 null - 不支持通配符或正则,必须写死字段名
- 子类继承时,
_hidden不会自动合并父类配置,需显式叠加
需要动态控制隐藏字段?用 toArray() 的 $options 参数
硬编码 _hidden 太死板——比如管理员导出要包含 last_login_ip,普通用户导出就得隐藏。这时得绕过实体自身配置,用 toArray() 的第二个参数手动指定排除项:
立即学习“PHP免费学习笔记(深入)”;
$data = $user->toArray([
'hidden' => ['password_hash', 'api_token']
]);
注意:hidden 选项会完全忽略实体类里的 $_hidden,二者不叠加。你传了 hidden,就只按你传的来。
- 适合 API 响应、导出 CSV 等按场景定制的场景
- 如果同时需要保留部分
_hidden字段 + 新增隐藏项,得手动合并数组:array_merge($user->getHidden(), ['extra_field']) - 该选项对虚拟字段(
_virtual)无效;虚拟字段是否导出,由$_virtual属性单独控制
为什么设置了 _hidden 却还是导出了字段?
常见原因不是配置错,而是字段压根没被实体“认作属性”。CakePHP 实体只序列化明确声明为“可访问”的字段,包括:
- 数据库表中存在的字段(通过
setSource()关联的表结构) - 在
$_accessible中设为true的字段(即使数据库没有) - 在
$_virtual中声明的虚拟字段
如果某个字段既不在数据库 schema 里,又没进 $_accessible 或 $_virtual,toArray() 根本看不到它,自然也谈不上隐藏——它压根不会出现。
典型误操作:$entity->set('temp_id', 123); 后期望 toArray() 导出它。结果发现没有。因为 temp_id 未声明可访问,得先加进 $_accessible:
protected $_accessible = [
'temp_id' => true,
// ... 其他字段
];
导出时想替换字段名(比如把 user_name 改成 name)?
_hidden 和 hidden 选项只管删,不管改。要重命名,得靠虚拟字段 + 访问器:
class User extends Entity
{
protected $_virtual = ['name'];
protected function _getName()
{
return $this->get('user_name');
}
}
这样 toArray() 输出里就会有 name 字段,而原始 user_name 可以放进 $_hidden 隐藏掉。
- 访问器方法名必须是
_get{FieldName}格式,且首字母大写 - 如果原字段是驼峰(
firstName),虚拟字段名建议保持一致风格(first_name或firstName),避免大小写混淆 - 虚拟字段无法被 ORM 查询条件使用,纯属导出层适配
真正难处理的是嵌套关联实体的字段隐藏——那得在关联实体里各自配 _hidden,主实体的 hidden 选项对关联内容无效。



















