最常用的是json_decode(json_encode($obj), true),速度快但会丢失private/protected属性、资源变null、浮点数精度偏差、循环引用报错;(array)$obj简单但键名含不可见字符、忽略__get();手写递归+get_object_vars()最可控但需处理closure/resource。

用 json_decode(json_encode($obj), true) 最快但丢精度
这是最常被搜到的“一行解”,适合临时调试或对数据结构不敏感的场景。它先把对象序列化成 JSON 字符串,再反解为关联数组。但要注意:
-
json_encode()会跳过不可见属性(如private和protected成员),除非类实现了JsonSerializable接口 - 资源类型(如
mysqli连接、文件句柄)直接变成null,不会报错但数据就没了 - 循环引用会触发
Recursion detected错误,得提前用debug_zval_count()或递归检测来防崩 - 浮点数可能因 JSON 双精度限制出现微小偏差,比如
1.0000000000000002变成1
用 (array) $obj 强转,简单但有隐藏规则
PHP 原生强制转换看起来最直白,但它不是“把对象所有字段摊平成数组”,而是按 PHP 内部存储结构映射——这导致很多意外:
- public 属性变成键名正常;
private属性键名会带"\0Classname\0"前缀,protected是"\0*\0",实际取值时得写全才能访问 - 动态属性(
$obj->new_prop = 'x')能转出来,但魔术方法__get()定义的“虚拟属性”完全不会出现 - 如果类定义了
__toString()且没其他 public 属性,强转后可能得到空数组,而不是字符串 - 在 PHP 8.2+ 中,对只读类(
readonly class)强转行为不变,但修改返回数组里的值不会影响原对象——这点容易误以为是深拷贝
手写递归遍历 + get_object_vars() 控制粒度
当你要精确控制哪些字段进数组、怎么处理嵌套对象、是否保留类型信息时,必须自己写逻辑。核心是 get_object_vars() ——它只返回当前对象的 public 属性(不含继承来的,也不含动态属性),配合 is_object() 判断递归即可:
function object_to_array($obj) {
if (!is_object($obj) && !is_array($obj)) return $obj;
if (is_object($obj)) $obj = get_object_vars($obj);
return array_map('object_to_array', $obj);
}
- 这个函数不会碰
private/protected,也不会执行任何魔术方法,干净但“太干净”——有时你需要它们 - 如果对象里有 Closure 或 resource,
array_map会报Object of class Closure could not be converted to string,得在递归前加类型过滤 - 性能上比
json方案慢 3–5 倍(实测 10k 简单对象),但可控性高得多 - 想兼容
__get()?得反射调用:(new ReflectionObject($obj))->getProperties(ReflectionProperty::IS_PUBLIC)配合isset()和__get()手动兜底
用 serialize() + 正则提取?别试了
网上有人用 serialize($obj) 后正则匹配 s:.*?} 来“提取字段”,这属于危险操作:
10分钟内自己学会PHP其中,第1篇为入门篇,主要包括了解PHP、PHP开发环境搭建、PHP开发基础、PHP流程控制语句、函数、字符串操作、正则表达式、PHP数组、PHP与Web页面交互、日期和时间等内容;第2篇为提高篇,主要包括MySQL数据库设计、PHP操作MySQL数据库、Cookie和Session、图形图像处理技术、文件和目录处理技术、面向对象、PDO数据库抽象层、程序调试与错误处理、A
立即学习“PHP免费学习笔记(深入)”;
- 序列化格式不是公开协议,PHP 小版本升级可能微调结构(比如 PHP 8.1 对
enum的序列化变化),正则立刻失效 - 字符串里含花括号、冒号或分号就会打断匹配,比如
$obj->name = "user{admin}";直接让正则崩掉 - 根本无法区分属性可见性,更别说处理对象嵌套——你拿到的只是字符串,不是结构化数据
- 就算一时跑通,下次维护的人看到这行正则,第一反应是删掉重写
真正需要持久化对象结构,请用 igbinary 扩展或自定义序列化接口,别碰正则解析序列化结果。
对象转数组这事,没有银弹。关键是想清楚:你要的是“能用就行”的快解,还是“以后改类结构也不崩”的稳解。前者选 json 方案并接受它的盲区;后者就得接受写几行判断逻辑的代价——而且得测试 private 属性、__get()、循环引用这三处,漏一个上线就出事。










