Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing PHP object to JSON

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?


Example

$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) } 

Addendum

1)

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.

2)

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

3)

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'         )));     }  } 
like image 324
Dan Lugg Avatar asked Jul 26 '11 21:07

Dan Lugg


People also ask

Can I JSON encode an object in PHP?

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.

What is JSON serialization in PHP?

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.

How does PHP serialize work?

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.

How to encode string to JSON in PHP?

$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.


2 Answers

In the simplest cases type hinting should work:

$json = json_encode( (array)$object ); 
like image 177
takeshin Avatar answered Sep 28 '22 08:09

takeshin



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; } 
like image 38
Wrikken Avatar answered Sep 28 '22 07:09

Wrikken