PHP递归将对象转换为数组

11
我将尝试递归地将一个PHP对象转换为数组。我编写的函数如下:
public function object_to_array($obj) {
    $array = (array) $obj;
    foreach ($array as $attribute) {
      if (is_array($attribute)) $attribute = $this->object_to_array($attribute);
      if (!is_string($attribute)) $attribute = (array) $attribute;
    }
    return $array;
}

然而,我仍然在我的外部数组中得到了对象。这是为什么?我的函数有问题吗?

2
你没有修改你的代码中的任何内容。 - zerkms
8个回答

10

这是我的版本。首先,它会测试传递的参数是否为数组或对象。如果是,则会将其转换为数组(如有必要),然后通过每个元素(按引用)并递归运行该函数。当它到达标量值时,它将只返回未修改的值。看起来好像有效 :-)

function object_to_array($obj) {
    //only process if it's an object or array being passed to the function
    if(is_object($obj) || is_array($obj)) {
        $ret = (array) $obj;
        foreach($ret as &$item) {
            //recursively process EACH element regardless of type
            $item = object_to_array($item);
        }
        return $ret;
    }
    //otherwise (i.e. for scalar values) return without modification
    else {
        return $obj;
    }
}

2
它的性能比json_decode()+json_encode()快1.5倍到2倍。 - MAChitgarha

8
你需要进行递归操作。
我能想到的最简短表述如下:
$toArray = function($x) use(&$toArray)
{
    return (is_scalar($x) || is_null($x))
        ? $x
        : array_map($toArray, (array) $x);
};

$array = $toArray($object);

2
这个代码运行良好,但是对于空值无法正常工作,所以我用 return (is_scalar($x) || is_null($x)) 替换了 return is_scalar($x) - 2pha
你说得对!我更新了我的答案。 - Sean Morris

3

您想检查它是否是对象而不是数组,尽管您可能会做两者:

if (is_object($attribute) || is_array($attribute)) $attribute = $this->object_to_array($attribute);
//I don't see a need for this
//if (!is_string($attribute)) $attribute = (array) $attribute;

来自阿齐兹·萨莱赫(Aziz Saleh),参考$attribute以便您可以修改它:

foreach ($array as &$attribute) {

第二部分检查它是否为字符串是因为我最终将其转换为json。如果它是一个字符串,我就不需要进一步拆分它。 - 735Tesla
如果它不是字符串,您可以使用(array)将其转换为数组。因此,整数、浮点数和布尔值将成为一个数组。 - AbraCadaver
我原以为我的意思是如果它不是字符串,那么将其转换为数组?!不是反转条件吗? - 735Tesla
是的,我编辑了它。它将整数、浮点数和布尔值转换为数组。 - AbraCadaver
谢谢,这个很好用!只是有点太好了,现在它也会转储用户的密码哈希和重置/持久化代码。显然这不应该在 API 中 :P 我得检查一下它是否是我不想包含在循环中的内容,并将其删除。 - 735Tesla

2

我找不到任何关于ArrayObject的适当文档。 - Elia Weiss
ArrayObject不能将子对象递归地转换为ArrayObjects,所以像$o = json_decode('{" 3:{" 2:{" 1":0}}}');这样的嵌套对象,$a = new ArrayObject($o);不起作用(只是执行$a =(array)$o的低效方式)。 - earboxer

1

1
我创建了这个函数,它简单而高效:
function object2array_recursive( $oject)
{
    $array = json_decode(json_encode($oject), true);
    return $array;
}

注意:这可能会导致无限循环和内存错误。


注意:这可能会导致无限循环和内存错误。 - Elia Weiss
我使用相同的代码将API(HTTP请求)中的stdClass对象转换为数组,就像它们稍后保存和检索JSON字段时将被转换的方式一样。 - El'
是的,这对于复杂对象来说并不安全,但以上任何答案都不能解决自引用的问题。例如:$a = new StdClass; $a->self = $a; - El'

0
你正在检查 is_array,但你应该检查 is_object - 如果它已经是一个数组,你可能不需要递归进入函数。你可以同时检查两个条件,这样对象数组也会被转换。

0

你需要做的是:


 foreach ($array as &$attribute) {

这将保留属性的更改,因为您正在通过引用使用它。

或者:

foreach ($array as $sub => $attribute) {
  if (is_array($attribute)) $array[$sub] = $this->object_to_array($attribute);
  if (!is_string($attribute)) $array[$sub] = (array) $attribute;
}

这将直接修改数组的子元素。我通常选择第二种解决方案,因为对我来说更加优雅。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接