(array)强制转换最简单但有陷阱:它只做浅拷贝,私有属性键名为\0classname\0property、受保护属性为\0*\0property,导致不可直接访问;get_object_vars()仅返回公有属性;完整导出需用reflectionclass或json中转(会丢失资源、性能差),推荐反射+递归实现深转。

直接用 (array) 强制转换最简单,但有陷阱——它只做浅拷贝,且对私有/受保护属性、对象嵌套、资源等处理不一致。
为什么 (array) 转换后看不到私有属性?
PHP 对象转数组时,(array) 会把私有属性名加上类名前缀(如 \0ClassName\0property),受保护属性加 \0*\0,导致键名“不可读”。这不是 bug,是 PHP 的序列化约定。
- 实际可用但难调试:转换后用
var_dump()能看到带前缀的键,但用isset($arr['name'])会失败 - 如果只是临时调试,可以用
get_object_vars()——但它只返回公有属性,忽略私有/受保护的 - 真正要完整导出,得配合
ReflectionClass遍历所有属性并手动赋值
json_decode(json_encode($obj), true) 真的可靠吗?
这个“JSON 中转法”能拿到所有可序列化的属性(包括私有和受保护),但代价明显:
- 会丢掉资源(
resource)、闭包、DateTime对象变成字符串、NaN/INF变成null - 遇到循环引用直接报错:
Exception: Type error: json_encode(): Nesting level too deep - 性能差:两次序列化/反序列化,大数据量对象明显卡顿
- 字符编码强制 UTF-8,原始字符串如果是 GBK 会乱码
怎么安全地实现深转数组(含私有属性)?
推荐用反射 + 递归,可控、无副作用。核心逻辑是:获取所有属性(不管访问控制),禁用访问检查,逐个读取值;遇到对象再递归调用自身。
function objectToArray($obj) {
if (!is_object($obj) && !is_array($obj)) return $obj;
if (is_object($obj)) {
$arr = [];
$ref = new ReflectionClass($obj);
foreach ($ref->getProperties() as $prop) {
$prop->setAccessible(true);
$arr[$prop->getName()] = objectToArray($prop->getValue($obj));
}
return $arr;
}
return array_map('objectToArray', $obj);
}
- 注意:PHP 7.4+ 才支持
$prop->getValue($obj)直接传对象;旧版本需先$prop->setValue($obj, null)再读 - 若对象里有
__sleep()或JsonSerializable,该函数不触发它们——这是优点也是缺点,看需求 - 不想自己写?Composer 安装
symfony/serializer,配置好后一行搞定:$serializer->normalize($obj)
真正麻烦的不是“怎么转”,而是“转完之后谁来保证结构稳定”。比如私有属性名改了、新增了不可序列化的依赖、或对象里混了 Closure——这些都不会报错,但结果会静默异常。动手前先想清楚:你到底需要数据快照,还是仅作日志输出?后者用 print_r($obj, true) 可能更实在。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











