Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing from JSON into PHP, with casting?

Tags:

Suppose I have a User class with 'name' and 'password' properties, and a 'save' method. When serializing an object of this class to JSON via json_encode, the method is properly skipped and I end up with something like {'name': 'testName', 'password': 'testPassword'}.

However, when deserializing via json_decode, I end up with a StdClass object instead of a User object, which makes sense but this means the object lacks the 'save' method. Is there any way to cast the resultant object as a User, or to provide some hint to json_decode as to what type of object I'm expecting?

like image 458
Jeroen van Delft Avatar asked Mar 18 '09 14:03

Jeroen van Delft


People also ask

How can I get JSON encoded data in PHP?

To receive JSON string we can use the “php://input” along with the function file_get_contents() which helps us receive JSON data as a file and read it into a string. Later, we can use the json_decode() function to decode the JSON string.

What is Deserializing a JSON?

The process whereby a lower-level format (e.g. that has been transferred over a network, or stored in a data store) is translated into a readable object or other data structure. In JavaScript, for example, you can deserialize a JSON string to an object by calling the function JSON. parse() .

How can you decode JSON string?

You just have to use json_decode() function to convert JSON objects to the appropriate PHP data type. Example: By default the json_decode() function returns an object. You can optionally specify a second parameter that accepts a boolean value. When it is set as “true”, JSON objects are decoded into associative arrays.


2 Answers

Old question, but maybe someone will find this useful.
I've created an abstract class with static functions that you can inherit on your object in order to deserialize any JSON into the inheriting class instance.

abstract class JsonDeserializer {     /**      * @param string|array $json      * @return $this      */     public static function Deserialize($json)     {         $className = get_called_class();         $classInstance = new $className();         if (is_string($json))             $json = json_decode($json);          foreach ($json as $key => $value) {             if (!property_exists($classInstance, $key)) continue;              $classInstance->{$key} = $value;         }          return $classInstance;     }     /**      * @param string $json      * @return $this[]      */     public static function DeserializeArray($json)     {         $json = json_decode($json);         $items = [];         foreach ($json as $item)             $items[] = self::Deserialize($item);         return $items;     } } 

You use it by inheriting it on a class which has the values that your JSON will have:

class MyObject extends JsonDeserializer {     /** @var string */     public $property1;      /** @var string */     public $property2;      /** @var string */     public $property3;      /** @var array */     public $array1; } 

Example usage:

$objectInstance = new MyObject(); $objectInstance->property1 = 'Value 1'; $objectInstance->property2 = 'Value 2'; $objectInstance->property3 = 'Value 3'; $objectInstance->array1 = ['Key 1' => 'Value 1', 'Key 2' => 'Value 2'];  $jsonSerialized = json_encode($objectInstance);  $deserializedInstance = MyObject::Deserialize($jsonSerialized); 

You can use the ::DeserializeArray method if your JSON contains an array of your target object.

Here's a runnable sample.

like image 134
René Sackers Avatar answered Sep 19 '22 15:09

René Sackers


Short answer: No (not that I know of*)

Long answer: json_encode will only serialize public variables. As you can see per the JSON spec, there is no "function" datatype. These are both reasons why your methods aren't serialized into your JSON object.

Ryan Graham is right - the only way to re-create these objects as non-stdClass instances is to re-create them post-deserialization.

Example

<?php  class Person {     public $firstName;     public $lastName;      public function __construct( $firstName, $lastName )     {         $this->firstName = $firstName;         $this->lastName = $lastName;     }      public static function createFromJson( $jsonString )     {         $object = json_decode( $jsonString );         return new self( $object->firstName, $object->lastName );     }      public function getName()     {         return $this->firstName . ' ' . $this->lastName;     } }  $p = new Person( 'Peter', 'Bailey' ); $jsonPerson = json_encode( $p );  $reconstructedPerson = Person::createFromJson( $jsonPerson );  echo $reconstructedPerson->getName(); 

Alternatively, unless you really need the data as JSON, you can just use normal serialization and leverage the __sleep() and __wakeup() hooks to achieve additional customization.

* In a previous question of my own it was suggested that you could implement some of the SPL interfaces to customize the input/output of json_encode() but my tests revealed those to be wild goose chases.

like image 20
Peter Bailey Avatar answered Sep 18 '22 15:09

Peter Bailey