PHP - 递归数组到对象?

时间:2011-01-25 05:55:39

标签: php object multidimensional-array stdclass

有没有办法在PHP中将多维array转换为stdClass对象?

转换为(object)似乎不会递归地运行。 json_decode(json_encode($array))产生我正在寻找的结果,但必须有更好的方法......

16 个答案:

答案 0 :(得分:55)

据我所知,没有预先构建的解决方案,所以你可以自己动手:

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;
} 

答案 1 :(得分:36)

我知道这个答案迟到了,但我会把它发布给那些正在寻找解决方案的人。

而不是所有这些循环等,您可以使用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;
}

希望这会有所帮助

答案 2 :(得分:7)

function toObject($array) {
    $obj = new stdClass();
    foreach ($array as $key => $val) {
        $obj->$key = is_array($val) ? toObject($val) : $val;
    }
    return $obj;
}

答案 3 :(得分:3)

/**
 * 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;
} 

答案 4 :(得分:2)

这里发布的其他一些解决方案无法从地图(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()

的解决方案

答案 5 :(得分:2)

您可以递归使用array_map

public static function _arrayToObject($array) {
    return is_array($array) ? (object) array_map([__CLASS__, __METHOD__], $array) : $array;
}

对我来说非常适合,因为它没有将Carbon对象转换为基本的stdClass(json编码/解码所做的)

答案 6 :(得分:2)

public static function _arrayToObject($array) {
    $json = json_encode($array);
    $object = json_decode($json);
    return $object
}

答案 7 :(得分:2)

将关联数组转换为对象的最简单方法是:

首先在json中对其进行编码,然后对其进行解码。

$objectArray = json_decode(json_encode($associtiveArray));

答案 8 :(得分:1)

您和许多其他人已经指出了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));    

答案 9 :(得分:1)

因为提到了性能,而且实际上在很多地方它应该很重要,所以我尝试在这里回答基准功能。

您可以看到代码和示例数据 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 函数,从而获得最佳性能,可能与您的配置无关。

答案 10 :(得分:0)

这是一个使用PHP内部(浅)数组到对象类型转换机制进行就地深度数组到对象转换的函数。 它仅在必要时创建新对象,从而最大限度地减少数据重复。

function toObject($array) {
    foreach ($array as $key=>$value)
        if (is_array($value))
            $array[$key] = toObject($value);
    return (object)$array;
}

警告 - 如果存在循环引用的风险,请不要使用此代码。

答案 11 :(得分:0)

编辑:此功能是从对象转换为数组。

来自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;
}

答案 12 :(得分:0)

这是一种平滑的方法,它可以处理深度很大的关联数组,并且不会覆盖不在数组中的对象属性。

    <?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 :(得分:0)

我能提出的最短时间:

array_walk_recursive($obj, function (&$val) { if (is_object($val)) $val = get_object_vars($val); });

答案 14 :(得分:0)

最近,但只是想提一下,你可以使用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开始可用

答案 15 :(得分:0)

我一直在寻找一种类似于 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);
    }
}

如果有人发现任何错误,请告诉我。