So, I wandered around php.net for information on serializing PHP objects in JSON when I came across the new JsonSerializable Interface . This is only PHP> = 5.4 , but I work in the 5.3.x environment.
How is this PHP functionality achieved <5.4
I haven't worked much with JSON yet, but I'm trying to maintain the API level in the application, and dumping a data object (which would otherwise be sent to the view) into JSON would be ideal.
If I try to serialize the object directly, it returns an empty JSON string; because I assume json_encode() does not know what to do with the object. Should I recursively dump an object into an array and then encode it?
Example
$data = new Mf_Data(); $data->foo->bar['hello'] = 'world';
echo json_encode($data) creates an empty object:
{}
var_dump($data) works as expected:
object(Mf_Data)#1 (5) { ["_values":"Mf_Data":private]=> array(0) { } ["_children":"Mf_Data":private]=> array(1) { [0]=> array(1) { ["foo"]=> object(Mf_Data)#2 (5) { ["_values":"Mf_Data":private]=> array(0) { } ["_children":"Mf_Data":private]=> array(1) { [0]=> array(1) { ["bar"]=> object(Mf_Data)#3 (5) { ["_values":"Mf_Data":private]=> array(1) { [0]=> array(1) { ["hello"]=> string(5) "world" } } ["_children":"Mf_Data":private]=> array(0) { } ["_parent":"Mf_Data":private]=> *RECURSION* ["_key":"Mf_Data":private]=> string(3) "bar" ["_index":"Mf_Data":private]=> int(0) } } } ["_parent":"Mf_Data":private]=> *RECURSION* ["_key":"Mf_Data":private]=> string(3) "foo" ["_index":"Mf_Data":private]=> int(0) } } } ["_parent":"Mf_Data":private]=> NULL ["_key":"Mf_Data":private]=> NULL ["_index":"Mf_Data":private]=> int(0) }
Adding
one)
So this is the toArray() function that I developed for the Mf_Data class:
public function toArray() { $array = (array) $this; array_walk_recursive($array, function (&$property) { if ($property instanceof Mf_Data) { $property = $property->toArray(); } }); return $array; }
However, since Mf_Data objects also have a reference to their parent (containing) object, this fails with recursion. Works like a charm, but when I remove the _parent link.
2)
Just to keep an eye on, the final function to convert the complex tree-node object I went with was:
// class name - Mf_Data // exlcuded properties - $_parent, $_index public function toArray() { $array = get_object_vars($this); unset($array['_parent'], $array['_index']); array_walk_recursive($array, function (&$property) { if (is_object($property) && method_exists($property, 'toArray')) { $property = $property->toArray(); } }); return $array; }
3)
I come again, a little cleaner implementation. Using interfaces to validate instanceof seems a lot cleaner than method_exists() (however method_exists() does cross-inherit / implementation).
Using unset() seemed a little dirty, and it seems that the logic should be reorganized into another method. However, this implementation copies the array of properties (due to array_diff_key ), so something needs to be considered.
interface ToMapInterface { function toMap(); function getToMapProperties(); } class Node implements ToMapInterface { private $index; private $parent; private $values = array(); public function toMap() { $array = $this->getToMapProperties(); array_walk_recursive($array, function (&$value) { if ($value instanceof ToMapInterface) { $value = $value->toMap(); } }); return $array; } public function getToMapProperties() { return array_diff_key(get_object_vars($this), array_flip(array( 'index', 'parent' ))); } }