最直接方案是json_encode+json_decode,可安全转任意深度纯键值对数组为stdClass对象树;ArrayObject适合仅顶层代理;手写递归需严格判断is_array;(object)$arr仅浅层转换;转自定义类需显式构造。

PHP json_decode 转多维数组为对象数组最直接
只要数组结构是纯键值对(不含资源、闭包、循环引用),json_encode + json_decode 是最快、最稳妥的通用方案。它把数组序列化成 JSON 字符串,再反解为 stdClass 对象树,天然支持任意深度嵌套。
注意:这个方法会丢失原始数组的数字键顺序(JSON 对象无序),但 PHP 中对象属性访问本身不依赖顺序,不影响使用。
示例:
$arr = ['name' => 'Alice', 'scores' => ['math' => 95, 'english' => 87]]; $obj = json_decode(json_encode($arr)); // $obj->name === 'Alice' // $obj->scores->math === 95
- 必须确保数组可 JSON 序列化;含
resource、closure或NaN会静默失败或报错 - 如果原数组有重复字符串键,后出现的会覆盖前面的(JSON 解析规则)
- 整数键会被转为字符串属性名(如
[0 => 'a']→{"0":"a"}),但 PHP 对象允许用$obj->{'0'}访问
用 ArrayObject 包装而不递归转换
如果你只是想让多维数组“看起来像对象”、支持 -> 语法访问顶层键,又不想改变内部结构(比如保留子数组用于后续 foreach),ArrayObject 是轻量替代方案。
立即学习“PHP免费学习笔记(深入)”;
它不会递归把子数组也变对象,只做一层包装,性能开销极小,且保留所有 PHP 数组特性(如 isset()、array_key_exists())。
示例:
$arr = ['user' => ['id' => 123], 'meta' => ['ts' => time()]]; $obj = new ArrayObject($arr, ArrayObject::ARRAY_AS_PROPS); // $obj->user 仍是 array,不是 stdClass // $obj->user['id'] === 123 ✅ // $obj->user->id ❌ 报错
- 适合需要混合访问方式(既用
->又用[])的场景 - 不能用于 JSON 输出(
json_encode($obj)默认输出空对象{},需手动设置标志位) - 不解决“深层对象化”需求,仅限顶层代理
手写递归函数时别忽略 null/bool/int/string 的类型穿透
自己写递归转换函数看似灵活,但容易在基础类型处理上出错——比如把 null、true、42、"hello" 也强行 new stdClass(),导致后续调用崩溃。
正确做法是只对 array 类型递归处理,其余类型原样返回。
示例(最小安全实现):
function array_to_object($arr) {
if (!is_array($arr)) return $arr;
$obj = new stdClass();
foreach ($arr as $k => $v) {
$obj->$k = array_to_object($v); // 递归只进 array 分支
}
return $obj;
}
- 漏掉
is_array()判断会导致foreach在 string 上报 Warning - 不要用
(object)$arr强转:它只转第一层,子数组仍为 array - 若需支持数字键作为属性,得用
$obj->{$k} = ...,否则 PHP 会警告“非法偏移类型”
遇到 __set/__get 自定义类时,别直接套用 json_decode
如果你的目标是转成某个具体类(如 User、Post)的实例数组,而不是 stdClass,json_decode($json, false, 512, JSON_OBJECT_AS_ARRAY) 这类技巧就失效了。
此时必须显式构造对象,并逐字段赋值,或借助 ReflectionClass + json_decode(..., true) 做映射。
-
json_decode默认只生成stdClass,无法指定目标类 - 第三方库如
jms/serializer或symfony/property-accessor可简化这事,但引入复杂度高 - 最简方式:先
json_decode($json, true)得到数组,再new User(...$data)或循环$user->$key = $value
深层嵌套对象初始化容易漏掉构造逻辑,比如子数组该转成 Address 还是保持数组,得按业务约定手工控制。这一步没法全自动,必须明确边界。



















