PHP - 递归数组到对象?
Posted
技术标签:
【中文标题】PHP - 递归数组到对象?【英文标题】:PHP - recursive Array to Object? 【发布时间】:2011-06-14 23:55:18 【问题描述】:有没有办法在 php 中将多维 array
转换为 stdClass
对象?
转换为(object)
似乎不能递归工作。 json_decode(json_encode($array))
产生了我正在寻找的结果,但必须有更好的方法......
【问题讨论】:
【参考方案1】:据我所知,没有预先构建的解决方案,所以你可以自己动手:
function array_to_object($array)
$obj = new stdClass;
foreach($array as $k => $v)
if(strlen($k))
if(is_array($v))
$obj->$k = array_to_object($v); //RECURSION
else
$obj->$k = $v;
return $obj;
【讨论】:
PHP 数组可以有空键,但对象不能有空属性。可能值得将else
更改为 elseif ($k !== '')
感谢您注意到仅使用 elseif 是无法完成的!
这个函数似乎会默默地删除具有空键的值。
嵌套数组有数字键会发生什么?我会选择 json 编码/解码解决方案。它可能不是最佳的,但却是最防弹的。
json编码/解码方法会将非StdClass对象转换为StdClass对象。【参考方案2】:
我知道这个答案来晚了,但我会把它发布给任何正在寻找解决方案的人。
您可以使用 PHP 的原生 json_* 函数来代替所有这些循环等。我有几个我经常使用的方便的功能
/**
* Convert an array into a stdClass()
*
* @param array $array The array we want to convert
*
* @return object
*/
function arrayToObject($array)
// First we convert the array to a json string
$json = json_encode($array);
// The we convert the json string to a stdClass()
$object = json_decode($json);
return $object;
/**
* Convert a object to an array
*
* @param object $object The object we want to convert
*
* @return array
*/
function objectToArray($object)
// First we convert the object into a json string
$json = json_encode($object);
// Then we convert the json string to an array
$array = json_decode($json, true);
return $array;
希望对你有帮助
【讨论】:
我很欣赏这个迟到总比从来没有好过的帖子,但我最初的问题引用了这种方法。 对于我是如何设法忽略这一点的,我没有任何有效的辩护:/ 我唯一能做的就是戴上眼镜并引用史蒂夫·厄克尔的话;我这样做了吗!?回到主题:据我所知,以我的拙见,这是最干净、最优化的方法。如果我错了,请纠正我:) 如果你从代码行来判断,它可能是最干净的,但涉及的开销要多得多。 Jacob Relkin 的答案更高效,也更容易编码。 这仅适用于兼容的 JSON 数据类型。如果你像我一样在多维数组中存储闭包,这将不起作用。【参考方案3】:您和许多其他人都指出了 JSON 内置函数 json_decode()
和 json_encode()
。您提到的方法有效,但并不完全:它不会将索引数组转换为对象,它们将保留为索引数组。但是,有一个技巧可以克服这个问题。你可以使用JSON_FORCE_OBJECT
常量:
// Converts an array to an object recursively
$object = json_decode(json_encode($array, JSON_FORCE_OBJECT));
提示:另外,如 here 所述,您可以使用 JSON 函数递归地将对象转换为数组:
// Converts an object to an array recursively
$array = json_decode(json_encode($object), true));
重要提示:如果您确实关心性能,请不要使用此方法。虽然它短而干净,但它是替代品中最慢的。请参阅此线程中的my other answer。
【讨论】:
【参考方案4】:function toObject($array)
$obj = new stdClass();
foreach ($array as $key => $val)
$obj->$key = is_array($val) ? toObject($val) : $val;
return $obj;
【讨论】:
这将为数组中的空键生成致命错误(无法访问空属性)。观察strlen in Jacob's answer【参考方案5】:您可以递归地使用array_map
:
public static function _arrayToObject($array)
return is_array($array) ? (object) array_map([__CLASS__, __METHOD__], $array) : $array;
非常适合我,因为它不会将例如 Carbon 对象转换为基本的 stdClass(json 编码/解码会这样做)
【讨论】:
当你在一个类中需要这种类型的实用程序时,这很简单,也很实用;很难找到其中的参考资料。为了清楚起见,您应该将其包装在示例类中。否则,CLASS、METHOD 魔法的好例子......你不会经常看到它。【参考方案6】:/**
* Recursively converts associative arrays to stdClass while keeping integer keys subarrays as arrays
* (lists of scalar values or collection of objects).
*/
function a2o( array $array )
$resultObj = new \stdClass;
$resultArr = array();
$hasIntKeys = false;
$hasStrKeys = false;
foreach ( $array as $k => $v )
if ( !$hasIntKeys )
$hasIntKeys = is_int( $k );
if ( !$hasStrKeys )
$hasStrKeys = is_string( $k );
if ( $hasIntKeys && $hasStrKeys )
$e = new \Exception( 'Current level has both integer and string keys, thus it is impossible to keep array or convert to object' );
$e->vars = array( 'level' => $array );
throw $e;
if ( $hasStrKeys )
$resultObj->$k = is_array( $v ) ? a2o( $v ) : $v;
else
$resultArr[$k] = is_array( $v ) ? a2o( $v ) : $v;
return ($hasStrKeys) ? $resultObj : $resultArr;
【讨论】:
【参考方案7】:此处发布的其他一些解决方案无法区分顺序数组(JS 中的 []
)和映射(JS 中的 )。对于许多用例,区分包含所有内容的 PHP 数组很重要从没有数字键的 PHP 数组中应该保留的顺序数字键,应该将其转换为对象。 (对于不属于上述两类的数组,我下面的解决方案是未定义的。)
json_decode(json_encode($x))
方法确实可以正确处理这两种类型,但不是最快的解决方案。尽管如此,它仍然很不错,在我的样本数据上每次运行总计 25µs(平均超过 1M 次运行,减去循环开销。)
我对递归转换器的几个变体进行了基准测试,最终得到以下结果。它重建所有数组和对象(执行深拷贝),但似乎比修改数组的替代解决方案更快。每次执行我的样本数据时,它的时钟为 11µs:
function array_to_object($x)
if (!is_array($x))
return $x;
elseif (is_numeric(key($x)))
return array_map(__FUNCTION__, $x);
else
return (object) array_map(__FUNCTION__, $x);
这是一个就地版本。在一些只需要转换小部分的大型输入数据上可能会更快,但在我的示例数据上,每次执行需要 15µs:
function array_to_object_inplace(&$x)
if (!is_array($x))
return;
array_walk($x, __FUNCTION__);
reset($x);
if (!is_numeric(key($x)))
$x = (object) $x;
我没有尝试使用 array_walk_recursive()
的解决方案
【讨论】:
第一种方法,只是创建了一个空对象。对我来说,第二种方法只能将最外层的关联数组变成stdClass
对象。其他所有内容在内部仍然是一个数组。
@KimberlyW 我刚刚测试了两者,它们仍然在 PHP 7 中工作。See this example【参考方案8】:
public static function _arrayToObject($array)
$json = json_encode($array);
$object = json_decode($json);
return $object
【讨论】:
这与this answer有何不同? @MAChitgarha 那里给出的答案使用循环机制。但这里的解决方案是使用比提到的答案更有效的内置函数 不,我指的不是公认的答案,而是 Ole 的。它说的和你的完全一样,但大约是 6 年前给出的。【参考方案9】:将关联数组转换为对象的最简单方法是:
先用json编码,再解码。
点赞$objectArray = json_decode(json_encode($associtiveArray));
【讨论】:
抱歉,您的回答对this answer没有任何帮助。【参考方案10】:因为提到了性能,实际上很多地方应该很重要,所以我尝试对这里回答的函数进行基准测试。
您可以看到代码和示例数据here in this gist。结果是用那里存在的数据进行测试的(一个随机的 JSON 文件,大小约为 200 KB),每个函数重复一千次,以使结果更准确。
以下是不同 PHP 配置的结果:
PHP 7.4.16(无 JIT)
$ php -dopcache.enable_cli=1 benchmark.php
pureRecursive(): Completed in 0.000560s
pureRecursivePreservingIntKeys(): Completed in 0.000580s
jsonEncode(): Completed in 0.002045s
jsonEncodeOptimized(): Completed in 0.002060s
jsonEncodeForceObject(): Completed in 0.002174s
arrayMap(): Completed in 0.000561s
arrayMapPreservingIntKeys(): Completed in 0.000592s
arrayWalkInplaceWrapper(): Completed in 0.001016s
PHP 8.0.2(无 JIT)
$ php -dopcache.enable_cli=1 benchmark.php
pureRecursive(): Completed in 0.000535s
pureRecursivePreservingIntKeys(): Completed in 0.000578s
jsonEncode(): Completed in 0.001991s
jsonEncodeOptimized(): Completed in 0.001990s
jsonEncodeForceObject(): Completed in 0.002164s
arrayMap(): Completed in 0.000579s
arrayMapPreservingIntKeys(): Completed in 0.000615s
arrayWalkInplaceWrapper(): Completed in 0.001040s
PHP 8.0.2(跟踪 JIT)
$ php -dopcache.enable_cli=1 -dopcache.jit_buffer_size=250M -dopcache.jit=tracing benchmark.php
pureRecursive(): Completed in 0.000422s
pureRecursivePreservingIntKeys(): Completed in 0.000410s
jsonEncode(): Completed in 0.002004s
jsonEncodeOptimized(): Completed in 0.001997s
jsonEncodeForceObject(): Completed in 0.002094s
arrayMap(): Completed in 0.000577s
arrayMapPreservingIntKeys(): Completed in 0.000593s
arrayWalkInplaceWrapper(): Completed in 0.001012s
如您所见,使用此基准测试最快的方法是纯递归 PHP 函数(由 @JacobRelkin 和 @DmitriySintsov 发布),尤其是在涉及 JIT 编译器时。对于json_*
函数,它们是最慢的。它们比纯方法慢了大约 3 到 4 倍(在 JIT 的情况下为 5 倍),这似乎令人难以置信。
需要注意的一点:如果您删除迭代(即每个函数只运行一次),或者甚至严格降低其计数,结果会有所不同。在这种情况下,arrayMap*()
变体胜过pureRecursive*()
变体(仍然json_*
函数方法应该是最慢的)。但是,您应该简单地忽略这些情况。在性能方面,可扩展性更为重要。
因此,在将数组转换为对象(反之亦然?)的情况下,您应该始终使用纯 PHP 函数,从而获得最佳性能,这可能与您的配置无关。
【讨论】:
【参考方案11】:这是一个使用 PHP 内部(浅)数组到对象类型转换机制进行就地深度数组到对象转换的函数。 它仅在必要时创建新对象,从而最大限度地减少数据重复。
function toObject($array)
foreach ($array as $key=>$value)
if (is_array($value))
$array[$key] = toObject($value);
return (object)$array;
警告 - 如果存在循环引用的风险,请勿使用此代码。
【讨论】:
【参考方案12】:这是一种平滑的方法,可以处理具有很大深度的关联数组,并且不会覆盖不在数组中的对象属性。
<?php
function setPropsViaArray( $a, $o )
foreach ( $a as $k => $v )
if ( is_array( $v ) )
$o->$k = setPropsViaArray( $v, ! empty ( $o->$k ) ? $o->$k : new stdClass() );
else
$o->$k = $v;
return $o;
;
setPropsViaArray( $newArrayData, $existingObject );
【讨论】:
【参考方案13】:晚了,但只想提一下,您可以使用 JSON 编码/解码来完全从/到数组转换:
//convert object $object into array
$array = json_decode(json_encode($object), true);
//convert array $array into object
$object = json_decode(json_encode($array));
json_encode 和 json_decode 函数从 php 5.2 开始可用
【讨论】:
问题本身已经提到了这一点,甚至在这个问题上还有another answer from 2012。【参考方案14】:编辑:这个函数是从对象到数组的转换。
来自https://forrst.com/posts/PHP_Recursive_Object_to_Array_good_for_handling-0ka
protected function object_to_array($obj)
$arrObj = is_object($obj) ? get_object_vars($obj) : $obj;
foreach ($arrObj as $key => $val)
$val = (is_array($val) || is_object($val)) ? $this->object_to_array($val) : $val;
$arr[$key] = $val;
return $arr;
【讨论】:
因为我误解了问题,这个fn是从对象到数组的转换。我会更新我的答案。【参考方案15】:我正在寻找一种类似于json_decode(json_encode($array))
的方式
这里大多数其他递归函数的问题是它们还将顺序数组转换为对象。但是,默认情况下 JSON 变体不会执行此操作。它只将关联数组转换为对象。
以下实现对我来说就像 JSON 变体一样:
function is_array_assoc ($arr)
if (!is_array($arr)) return false;
foreach (array_keys($arr) as $k => $v) if ($k !== $v) return true;
return false;
// json_decode(json_encode($array))
function array_to_object ($arr)
if (!is_array($arr) && !is_object($arr)) return $arr;
$arr = array_map(__FUNCTION__, (array)$arr);
return is_array_assoc($arr) ? (object)$arr : $arr;
// json_decode(json_encode($array, true))
// json_decode(json_encode($array, JSON_OBJECT_AS_ARRAY))
function object_to_array ($obj)
if (!is_object($obj) && !is_array($obj)) return $obj;
return array_map(__FUNCTION__, (array)$obj);
如果你想将函数作为一个类:
class ArrayUtils
public static function isArrAssoc ($arr)
if (!is_array($arr)) return false;
foreach (array_keys($arr) as $k => $v) if ($k !== $v) return true;
return false;
// json_decode(json_encode($array))
public static function arrToObj ($arr)
if (!is_array($arr) && !is_object($arr)) return $arr;
$arr = array_map([__CLASS__, __METHOD__], (array)$arr);
return self::isArrAssoc($arr) ? (object)$arr : $arr;
// json_decode(json_encode($array, true))
// json_decode(json_encode($array, JSON_OBJECT_AS_ARRAY))
public static function objToArr ($obj)
if (!is_object($obj) && !is_array($obj)) return $obj;
return array_map([__CLASS__, __METHOD__], (array)$obj);
如果有人发现任何错误,请告诉我。
【讨论】:
【参考方案16】:我能想到的最短的:
array_walk_recursive($obj, function (&$val) if (is_object($val)) $val = get_object_vars($val); );
【讨论】:
这是为了将对象转换为数组,而不是相反。以上是关于PHP - 递归数组到对象?的主要内容,如果未能解决你的问题,请参考以下文章