PHP - 递归数组到对象?

发布于 2024-10-14 06:33:48 字数 159 浏览 3 评论 0原文

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

强制转换为 (object) 似乎无法递归工作。 json_decode(json_encode($array)) 产生我正在寻找的结果,但必须有更好的方法......

Is there a way to convert a multidimensional array to a stdClass object in PHP?

Casting as (object) doesn't seem to work recursively. json_decode(json_encode($array)) produces the result I'm looking for, but there has to be a better way...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

浅听莫相离 2024-10-21 06:33:48

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

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

As far as I can tell, there is no prebuilt solution for this, so you can just roll your own:

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;
}
沧桑㈠ 2024-10-21 06:33:48

我知道这个答案来晚了,但我会将其发布给任何正在寻找解决方案的人。

您可以使用 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;
}

希望这会有所帮助

I know this answer is coming late but I'll post it for anyone who's looking for a solution.

Instead of all this looping etc, you can use PHP's native json_* function. I've got a couple of handy functions that I use a lot

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

Hope this can be helpful

猫腻 2024-10-21 06:33:48

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

重要提示:如果您确实关心性能,请不要使用此方法。虽然它简短而干净,但它是替代方案中最慢的。请参阅此主题中与此相关的我的其他答案

You and many others have pointed to the JSON built-in functions, json_decode() and json_encode(). The method which you have mentioned works, but not completely: it won't convert indexed arrays to objects, and they will remain as indexed arrays. However, there is a trick to overcome this problem. You can use JSON_FORCE_OBJECT constant:

// Converts an array to an object recursively
$object = json_decode(json_encode($array, JSON_FORCE_OBJECT));

Tip: Also, as mentioned here, you can convert an object to array recursively using JSON functions:

// Converts an object to an array recursively
$array = json_decode(json_encode($object), true));    

Important Note: If you do care about performance, do not use this method. While it is short and clean, but it is the slowest among alternatives. See my other answer in this thread relating this.

人间不值得 2024-10-21 06:33:48
function toObject($array) {
    $obj = new stdClass();
    foreach ($array as $key => $val) {
        $obj->$key = is_array($val) ? toObject($val) : $val;
    }
    return $obj;
}
function toObject($array) {
    $obj = new stdClass();
    foreach ($array as $key => $val) {
        $obj->$key = is_array($val) ? toObject($val) : $val;
    }
    return $obj;
}
烦人精 2024-10-21 06:33:48

您可以递归地使用 array_map:

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

对我来说非常适合,因为它不会将例如 Carbon 对象转换为基本的 stdClass(json 编码/解码会这样做)

You can use the array_map recursively:

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

Works perfect for me since it doesn't cast for example Carbon objects to a basic stdClass (which the json encode/decode does)

潇烟暮雨 2024-10-21 06:33:48
/**
 * 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;
} 
/**
 * 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()<的解决方案/代码>

Some of the other solutions posted here fail to tell apart sequential arrays (what would be [] in JS) from maps ({} in JS.) For many use cases it's important to tell apart PHP arrays that have all sequential numeric keys, which should be left as such, from PHP arrays that have no numeric keys, which should be converted to objects. (My solutions below are undefined for arrays that don't fall in the above two categories.)

The json_decode(json_encode($x)) method does handle the two types correctly, but is not the fastest solution. It's still decent though, totaling 25µs per run on my sample data (averaged over 1M runs, minus the loop overhead.)

I benchmarked a couple of variations of the recursive converter and ended up with the following. It rebuilds all arrays and objects (performing a deep copy) but seems to be faster than alternative solutions that modify the arrays in place. It clocks at 11µs per execution on my sample data:

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

Here is an in-place version. It may be faster on some large input data where only small parts need to be converted, but on my sample data it took 15µs per execution:

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

I did not try out solutions using array_walk_recursive()

软的没边 2024-10-21 06:33:48

因为提到了性能,而且实际上它在很多地方都应该很重要,所以我尝试对这里回答的函数进行基准测试。

您可以在此要点中查看代码和示例数据。使用现有数据(随机 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 函数,以获得最佳性能,也许与您的配置无关。

Because the performance is mentioned, and in fact it should be important in many places, I tried to benchmark functions answered here.

You can see the code and sample data here in this gist. The results are tested with the data exists there (a random JSON file, around 200 KB in size), and each function repeated one thousand times, for the results to be more accurate.

Here are the results for different PHP configurations:

PHP 7.4.16 (no 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 (no 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 (tracing 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

As you see, the fastest method with this benchmark is pure recursive PHP functions (posted by @JacobRelkin and @DmitriySintsov), especially when it comes to the JIT compiler. When it comes to json_* functions, they are the slowest ones. They are about 3x-4x (in the case of JIT, 5x) slower than the pure method, which may seem unbelievable.

One thing to note: If you remove iterations (i.e. run each function only one time), or even strictly lower its count, the results would differ. In such cases, arrayMap*() variants win over pureRecursive*() ones (still json_* functions method should be the slowest). But, you should simply ignore these cases. In the terms of performance, scalability is much more important.

As a result, in the case of converting arrays to object (and vice versa?), you should always use pure PHP functions, resulting in the best performance, perhaps independent from your configurations.

吻风 2024-10-21 06:33:48

我一直在寻找一种类似于 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(__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(__METHOD__, (array)$obj);
    }
}

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

I was looking for a way that acts like json_decode(json_encode($array))

The problem with most other recursive functions here is that they also convert sequential arrays into objects. However, the JSON variant does not do this by default. It only converts associative arrays into objects.

The following implementation works for me like the JSON variant:

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

If you want to have the functions as a class:

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(__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(__METHOD__, (array)$obj);
    }
}

If anyone finds any mistakes please let me know.

七七 2024-10-21 06:33:48

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

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

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

Here's a function to do an in-place deep array-to-object conversion that uses PHP internal (shallow) array-to-object type casting mechanism.
It creates new objects only when necessary, minimizing data duplication.

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

Warning - do not use this code if there is a risk of having circular references.

魔法少女 2024-10-21 06:33:48

编辑:此函数是从对象到数组的转换。

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

EDIT: This function is conversion from object to array.

From 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;
}
乞讨 2024-10-21 06:33:48
/**
 * Convert a multidimensional array to an object recursively.
 * For any arrays inside another array, the result will be an array of objects.
 *
 * @author Marcos Freitas
 * @param array|any $props
 * @return array|any
 */
function array_to_object($props, $preserve_array_indexes = false) {
    $obj = new \stdClass();

    if (!is_array($props)) {
        return $props;
    }

    foreach($props as $key => $value) {

        if (is_numeric($key) && !$preserve_array_indexes) {
            if(!is_array($obj)) {
                $obj = [];
            }

            $obj[] = $this->array_to_object($value);
            continue;
        }

        $obj->{$key} = is_array($value) ? $this->array_to_object($value) : $value;
    }

    return $obj;
}
/**
 * Convert a multidimensional array to an object recursively.
 * For any arrays inside another array, the result will be an array of objects.
 *
 * @author Marcos Freitas
 * @param array|any $props
 * @return array|any
 */
function array_to_object($props, $preserve_array_indexes = false) {
    $obj = new \stdClass();

    if (!is_array($props)) {
        return $props;
    }

    foreach($props as $key => $value) {

        if (is_numeric($key) && !$preserve_array_indexes) {
            if(!is_array($obj)) {
                $obj = [];
            }

            $obj[] = $this->array_to_object($value);
            continue;
        }

        $obj->{$key} = is_array($value) ? $this->array_to_object($value) : $value;
    }

    return $obj;
}
心意如水 2024-10-21 06:33:48

对我来说,关于 json_decode(json_encode($input)) 最困扰我的不是性能,而是它破坏了我的数组中的自定义类(它将它们转换为 stdClass 实例)。

从 PHP 8.1 开始,有函数 array_is_list 来检测非关联数组。这帮助我构建了 json_decode(json_encode($value)) 的复制品,它将保留自定义类实例:

class Utils {
    /**
     * Re-implementation of json_decode(json_encode($value)), with the added benefit of 
     * keeping custom classes intact. Uses `array_is_list` to detect non-associative arrays.
     * Required PHP version: >= 8.1
     */
    public static function to_object($input): array|\stdClass {
        if (!is_array($input) && !($input instanceof \stdClass)) {
            return $input;
        }
        // keep non-associative arrays as such, otherwise use a stdClass
        $result = is_array($input) && array_is_list($input) ? [] : new \stdClass();
        foreach ($input as $key => $value) {
            // If the value is an array or a standard object, recursively convert it
            if (is_array($value) || $value instanceof \stdClass) {
                $value = call_user_func(__METHOD__, $value);
            }

            // Add the value to the result (either an stdClass or a non-associative array)
            if ($result instanceof \stdClass) {
                $result->$key = $value;
            } else {
                $result[$key] = $value;
            }

        }
        return $result;
    }
}

过于简单化的使用示例:

Utils::to_object(['foo' => 'bar', 'baz' => ['bat']]);

一个包含简单数组、关联数组和stdClass 可以在这里找到:https://onlinephp.io/c/26a53

For me, the thing that bothers me most about json_decode(json_encode($input)) is not performance, but rather the fact that it destroys custom classes in my arrays (it converts them to stdClass instances).

Since PHP 8.1, there is the function array_is_list to detect non-associative arrays. This helped me to build a replicate of json_decode(json_encode($value)) that will preserve custom class instances:

class Utils {
    /**
     * Re-implementation of json_decode(json_encode($value)), with the added benefit of 
     * keeping custom classes intact. Uses `array_is_list` to detect non-associative arrays.
     * Required PHP version: >= 8.1
     */
    public static function to_object($input): array|\stdClass {
        if (!is_array($input) && !($input instanceof \stdClass)) {
            return $input;
        }
        // keep non-associative arrays as such, otherwise use a stdClass
        $result = is_array($input) && array_is_list($input) ? [] : new \stdClass();
        foreach ($input as $key => $value) {
            // If the value is an array or a standard object, recursively convert it
            if (is_array($value) || $value instanceof \stdClass) {
                $value = call_user_func(__METHOD__, $value);
            }

            // Add the value to the result (either an stdClass or a non-associative array)
            if ($result instanceof \stdClass) {
                $result->$key = $value;
            } else {
                $result[$key] = $value;
            }

        }
        return $result;
    }
}

Overly simplistic usage example:

Utils::to_object(['foo' => 'bar', 'baz' => ['bat']]);

A live demo with tests for a simple array, an associative array and a stdClass can be found here: https://onlinephp.io/c/26a53

自在安然 2024-10-21 06:33:48

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

    <?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 );

Here is a smooth way to do it that can handle an associative array with great depth and doesn't overwrite object properties that are not in the 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 );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文