有没有办法将多维转换为PHParray
中的对象?stdClass
铸造 as(object)
似乎不能递归地工作。 json_decode(json_encode($array))
产生我正在寻找的结果,但必须有更好的方法......
有没有办法将多维转换为PHParray
中的对象?stdClass
铸造 as(object)
似乎不能递归地工作。 json_decode(json_encode($array))
产生我正在寻找的结果,但必须有更好的方法......
据我所知,没有预先构建的解决方案,所以你可以自己动手:
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 的原生 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;
}
希望这会有所帮助
您和许多其他人都指出了 JSON 内置函数,json_decode()
并且json_encode()
. 您提到的方法有效,但并不完全:它不会将索引数组转换为对象,它们将保留为索引数组。但是,有一个技巧可以克服这个问题。您可以使用JSON_FORCE_OBJECT
常量:
// Converts an array to an object recursively
$object = json_decode(json_encode($array, JSON_FORCE_OBJECT));
提示:此外,正如这里提到的,您可以使用 JSON 函数递归地将对象转换为数组:
// Converts an object to an array recursively
$array = json_decode(json_encode($object), true));
重要提示:如果您确实关心性能,请不要使用此方法。虽然它又短又干净,但它是替代品中最慢的。请参阅我在此线程中的其他答案。
function toObject($array) {
$obj = new stdClass();
foreach ($array as $key => $val) {
$obj->$key = is_array($val) ? toObject($val) : $val;
}
return $obj;
}
您可以array_map
递归地使用:
public static function _arrayToObject($array) {
return is_array($array) ? (object) array_map([__CLASS__, __METHOD__], $array) : $array;
}
非常适合我,因为它不会将例如 Carbon 对象转换为基本的 stdClass(json 编码/解码会这样做)
/**
* 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;
}
此处发布的其他一些解决方案无法将顺序数组([]
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()
public static function _arrayToObject($array) {
$json = json_encode($array);
$object = json_decode($json);
return $object
}
将关联数组转换为对象的最简单方法是:
先用json编码,再解码。
喜欢$objectArray = json_decode(json_encode($associtiveArray));
因为提到了性能,实际上很多地方应该很重要,所以我尝试对这里回答的函数进行基准测试。
您可以在此 gist中查看代码和示例数据。使用那里存在的数据(一个随机的 JSON 文件,大小约为 200 KB)对结果进行测试,每个函数重复一千次,以使结果更准确。
以下是不同 PHP 配置的结果:
$ 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 -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 -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 函数,从而获得最佳性能,这可能与您的配置无关。
编辑:这个函数是从对象到数组的转换。
来自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;
}
这是一个使用 PHP 内部(浅)数组到对象类型转换机制进行就地深度数组到对象转换的函数。它仅在必要时创建新对象,从而最大限度地减少数据重复。
function toObject($array) {
foreach ($array as $key=>$value)
if (is_array($value))
$array[$key] = toObject($value);
return (object)$array;
}
警告 - 如果存在循环引用的风险,请勿使用此代码。
这是一种平滑的方法,可以处理具有很大深度的关联数组,并且不会覆盖不在数组中的对象属性。
<?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 );
迟到了,但只想提一下,您可以使用 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 开始可用
我一直在寻找一种方式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);
}
}
如果有人发现任何错误,请告诉我。
我能想到的最短的:
array_walk_recursive($obj, function (&$val) { if (is_object($val)) $val = get_object_vars($val); });