PHP Recursively Convert Object to Array
Asked Answered
M

8

13

I am trying to recursively convert a php object to an array. The function I wrote is this:

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

However, I still end up with objects in my outer array. Why is this? Is my function incorrect?

Misgovern answered 27/3, 2014 at 0:49 Comment(1)
You aren't modifying anything in your codeWeeden
F
3

You want to check if it's an object not an array, though you might do both:

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;

And from Aziz Saleh, reference $attribute so you can modify it:

foreach ($array as &$attribute) {
Fitzsimmons answered 27/3, 2014 at 0:53 Comment(5)
The second part checking if it's a string is because I'm ultimately turning it into json. If it's a string I don't need to split it further.Misgovern
If its not a string you are casting it to an array with (array). So ints, floats, booleans will be an array.Fitzsimmons
I thought that I was saying if it is not a string, then cast it to an array? Doesn't ! invert the condition?Misgovern
Yes, i edited it. It casts ints, floats, booleans to an array.Fitzsimmons
Thanks. This works great! A bit too well though, now it also dumps the user's password hashes and reset/persist codes. Obviously that shouldn't be in the api :P I have to check if it is something I don't want to be included in the loop and remove it.Misgovern
S
12

Here's my version. First it will test if the parameter passed is an array or object. If so it'll convert to array (if necessary) then run through each element (by reference) and recursively run the function on it. When it gets to a scalar value it will just return the value unmodified. Seems to work :-)

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;
    }
}
Syndesis answered 10/1, 2019 at 14:39 Comment(1)
It performs 1.5x to 2x faster than json_decode() + json_encode().Izaguirre
A
8

You need to operate recursively.

This is the shortest I could come up with:

$toArray = function($x) use(&$toArray)
{
    return (is_scalar($x) || is_null($x))
        ? $x
        : array_map($toArray, (array) $x);
};

$array = $toArray($object);
Angell answered 28/11, 2018 at 8:52 Comment(2)
this worked well except for null values so I replaced return is_scalar($x) with return (is_scalar($x) || is_null($x))Interlaken
You're right! I updated my answer.Angell
F
3

You want to check if it's an object not an array, though you might do both:

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;

And from Aziz Saleh, reference $attribute so you can modify it:

foreach ($array as &$attribute) {
Fitzsimmons answered 27/3, 2014 at 0:53 Comment(5)
The second part checking if it's a string is because I'm ultimately turning it into json. If it's a string I don't need to split it further.Misgovern
If its not a string you are casting it to an array with (array). So ints, floats, booleans will be an array.Fitzsimmons
I thought that I was saying if it is not a string, then cast it to an array? Doesn't ! invert the condition?Misgovern
Yes, i edited it. It casts ints, floats, booleans to an array.Fitzsimmons
Thanks. This works great! A bit too well though, now it also dumps the user's password hashes and reset/persist codes. Obviously that shouldn't be in the api :P I have to check if it is something I don't want to be included in the loop and remove it.Misgovern
R
3

$array = json_decode(json_encode($object), true);

Credit to:https://gist.github.com/victorbstan/744478

Reimer answered 12/6, 2023 at 14:51 Comment(0)
V
2

Try using PHPs built in ArrayObject. It allows you to treat an object as an array.

http://www.php.net/manual/en/class.arrayobject.php

Ventris answered 27/3, 2014 at 0:53 Comment(2)
I couldn't find any proper documentation to ArrayObjectReprisal
ArrayObject doesn't recursively convert subobjects into ArrayObjects, so $a = new ArrayObject($o); would not work for a nested object like $o = json_decode('{"3":{"2":{"1":0}}}'); (and would just be a less efficient way of doing $a = (array) $o;)Currin
C
1

i created this function
that's simple and efficient :

function object2array_recursive( $oject)
{
    $array = json_decode(json_encode($oject), true);
    return $array;
}

NOTE: this might cause endless loop and out of memory error

Crocoite answered 4/7, 2019 at 14:53 Comment(3)
NOTE: this might cause endless loop and out of memory errorReprisal
I use same code to convert stdClass objects from API (http requests) into array, same way as they will be converted later when saved and retrived from database JSON field.Koehn
And yes, this is not safe for complex objects, but none of the answers above do not solve even self references. Eg: $a = new StdClass; $a->self = $a;Koehn
F
0

You need to do:

 foreach ($array as &$attribute) {

This will keep changes to attribute since you are using it by reference.

Or:

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

This will directly modify the array sub element. I usually go for the second solution as it is more classier to me.

Freehanded answered 27/3, 2014 at 0:53 Comment(0)
D
0

You are checking is_array, when you should be checking is_object - if it's already an array, you probably don't need to recurse into the function. You could check both, so that an array of objects would also get converted.

Dunant answered 27/3, 2014 at 0:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.