So I was wandering around php.net for information about serializing PHP objects to JSON, when I stumbled across the new JsonSerializable Interface. It's only PHP >= 5.4 though, and I'm running in a 5.3.x environment.
How is this sort of functionality achieved PHP < 5.4?
I've not worked much with JSON yet, but I'm trying to support an API layer in an application, and dumping the data object (that would otherwise be sent to the view) into JSON would be perfect.
If I attempt to serialize the object directly, it returns an empty JSON string; which is because I assume json_encode()
doesn't know what the heck to do with the object. Should I recursively reduce the object into an array, and then encode that?
$data = new Mf_Data(); $data->foo->bar['hello'] = 'world';
echo json_encode($data)
produces an empty object:
{}
var_dump($data)
however, 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) }
So this is the toArray()
function I've devised 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 the Mf_Data
objects also have a reference to their parent (containing) object, this fails with recursion. Works like a charm though when I remove the _parent
reference.
Just to follow up, the final function to transform a 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; }
I'm following up again, with a bit cleaner of an implementation. Using interfaces for an instanceof
check seems much cleaner than method_exists()
(however method_exists()
does cross-cut inheritance/implementation).
Using unset()
seemed a bit messy too, and it seems that logic should be refactored into another method. However, this implementation does copy the property array (due to array_diff_key
), so something to consider.
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' ))); } }
To encode objects into a JSON formatted string in PHP, you can use the json_encode(value, options, depth) function. The first parameter specifies the PHP object to encode. You can control how the PHP object will be encoded into JSON by passing a combination of bitmasks in the second parameter.
The JsonSerializable::jsonSerialize() function is an inbuilt function in PHP which is used to serialize the JSON object to a value that can be serialized natively by using json_encode() function. Syntax: mixed JsonSerializable::jsonSerialize( void ) Parameters: This function does not accept any parameters.
The serialize() function converts a storable representation of a value. To serialize data means to convert a value to a sequence of bits, so that it can be stored in a file, a memory buffer, or transmitted across a network.
$jObj = json_decode($jsonString); And to convert it to a associative array, set the second parameter to true : $jArr = json_decode($jsonString, true); By the way to convert your mentioned string back to either of those, you should have a valid JSON string.
In the simplest cases type hinting should work:
$json = json_encode( (array)$object );
edit: it's currently 2016-09-24, and PHP 5.4 has been released 2012-03-01, and support has ended 2015-09-01. Still, this answer seems to gain upvotes. If you're still using PHP < 5.4, your are creating a security risk and endagering your project. If you have no compelling reasons to stay at <5.4, or even already use version >= 5.4, do not use this answer, and just use PHP>= 5.4 (or, you know, a recent one) and implement the JsonSerializable interface
You would define a function, for instance named getJsonData();
, which would return either an array, stdClass
object, or some other object with visible parameters rather then private/protected ones, and do a json_encode($data->getJsonData());
. In essence, implement the function from 5.4, but call it by hand.
Something like this would work, as get_object_vars()
is called from inside the class, having access to private/protected variables:
function getJsonData(){ $var = get_object_vars($this); foreach ($var as &$value) { if (is_object($value) && method_exists($value,'getJsonData')) { $value = $value->getJsonData(); } } return $var; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With