Unidimensional arrays and objects can be converted by casting (e.g.
$array = (array) $object; /
$object = (object) $array;) but if multidimensional only the first tier is converted. Here’s the solution!
You could iterate through each array item / object property and cast it, then recursively check if it has children which need casting too, but PHP’s JSON functions offer an easier way.
The following array will be our test data:
$array = [ 'foo' => true, 'bar' => [ 'fizz' => 12, 'buzz' => 'ban', ], ];
Why casting doesn’t work
Casting only changes the variable itself, but in a multidimensional array/object the items/properties are variables in themselves which is why casting doesn’t work. For example, running
var_dump((object) $array); only yields:
object(stdClass) public 'foo' => boolean true public 'bar' => array (size=2) 'fizz' => int 12 'buzz' => string 'ban' (length=3)
The array has been converted to an object but
bar is still an array!
Converting an Array to an Object
This is the easiest conversion —
json_encode() converts an array to json and
json_decode() converts json to a
$object = json_decode(json_encode($array));
var_dump()ing the above yields:
object(stdClass) public 'foo' => boolean true public 'bar' => object(stdClass) public 'fizz' => int 12 public 'buzz' => string 'ban' (length=3)
Note how all levels have been converted —a multidimensional array has become a multidimensional object! What’s happening is very simple:
$array is converted to json with
json_encode(), then that json is converted to an object with
Converting an Object to an Array
This is a slightly different case in which we can take advantage of
json_decode()‘s second param
$assoc. It defaults to
false and, according to the manual, “When TRUE, returned objects will be converted into associative arrays”:
$array= json_decode(json_encode($object), true);
var_dump()ing the above yields:
array (size=2) 'foo' => boolean true 'bar' => array (size=2) 'fizz' => int 12 'buzz' => string 'ban' (length=3)
Again, note how all levels have been converted. What’s happening this time is that
$object is converted to json with
json_encode() like before, but this time we convert that json into an associative array with
json_decode() and passing
true as its second parameter.
Merge Multidimensional Objects
A problem I came across recently involved having to merge two multidimensional objects, both containing other objects, strings, integers and booleans. One object contained user settings and the other contained the default settings; merging the two (overwriting the defaults with the user settings) would ensure the correct settings were used and that all settings had a variable — even if it had been added during an update and the user hadn’t saved a value for it!
The solution is to ensure both objects are arrays, then use
array_replace_recursive() to merge the two. It replaces array keys with those from subsequent arrays, i.e. array in param 1 will be overwritten by those in param 2 if the keys are the same (
array_merge(), recursively). So if you pass a defaults array and a user settings array, the result will contain every key, prioritising user settings.
// Array of default settings $defaults = ; // Associative array of user settings from stored json $options = json_decode($user_settings_json, true); // Merge defaults & options, prioritising options $options = array_replace_recursive($defaults, $options); // Convert options back to an object $options = json_decode(json_encode($options));
Multidimensional anythings are a strange beast but are brilliant at modelling complicated data structures. I’d call them a “necessary evil” but I don’t think they’re evil at all, just a bit tricky at times.
If you’ve been using
unserialize to convert variables into storable/transferable strings, try using json instead. You won’t get a headache when linebreaks yield anomalous errors and you’ll be better-prepared if an API comes into play!
One final thing:
json_encode() has its own trick up its sleeve —if you pass
JSON_PRETTY_PRINT as a second parameter you get unminified json with spaces and newlines and everything! Just make sure you wrap it in
<pre> for maximum win:
<pre><?=json_encode(array('foo', 'bar'), JSON_PRETTY_PRINT);></pre>