Deserializing from JSON into PHP, with casting?

前端 未结 12 2020
既然无缘
既然无缘 2021-01-31 04:38

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 pro

相关标签:
12条回答
  • 2021-01-31 04:46

    Below is an example of using both static (i.e. you know the class type in code) and dynamic (i.e. you only know the class type at runtime) to deserialize JSON back into a PHP object:

    Code

    <?php
    
    class Car
    {
        private $brand;
        private $model;
        private $year;
    
        public function __construct($brand, $model, $year)
        {
            $this->brand = $brand;
            $this->model = $model;
            $this->year = $year;
        }
    
        public function toJson()
        {
            $arr = array(
                'brand' => $this->brand,
                'model' => $this->model,
                'year' => $this->year,
            );
    
            return json_encode($arr);
        }
    
        public static function fromJson($json)
        {
            $arr = json_decode($json, true);
    
            return new self(
                $arr['brand'],
                $arr['model'],
                $arr['year']
            );
        }
    }
    
    // original object
    echo 'car1: ';
    $car1 = new Car('Hyundai', 'Tucson', 2010);
    var_dump($car1);
    
    // serialize
    echo 'car1class: ';
    $car1class = get_class($car1); // need the class name for the dynamic case below. this would need to be bundled with the JSON to know what kind of class to recreate.
    var_dump($car1class);
    
    echo 'car1json: ';
    $car1Json = $car1->toJson();
    var_dump($car1Json);
    
    // static recreation with direct invocation. can only do this if you know the class name in code.
    echo 'car2: ';
    $car2 = Car::fromJson($car1Json);
    var_dump($car2);
    
    // dynamic recreation with reflection. can do this when you only know the class name at runtime as a string.
    echo 'car3: ';
    $car3 = (new ReflectionMethod($car1class, 'fromJson'))->invoke(null, $car1Json);
    var_dump($car3);
    

    Output

    car1: object(Car)#1 (3) {
      ["brand":"Car":private]=>
      string(7) "Hyundai"
      ["model":"Car":private]=>
      string(6) "Tucson"
      ["year":"Car":private]=>
      int(2010)
    }
    car1class: string(3) "Car"
    car1json: string(48) "{"brand":"Hyundai","model":"Tucson","year":2010}"
    car2: object(Car)#2 (3) {
      ["brand":"Car":private]=>
      string(7) "Hyundai"
      ["model":"Car":private]=>
      string(6) "Tucson"
      ["year":"Car":private]=>
      int(2010)
    }
    car3: object(Car)#4 (3) {
      ["brand":"Car":private]=>
      string(7) "Hyundai"
      ["model":"Car":private]=>
      string(6) "Tucson"
      ["year":"Car":private]=>
      int(2010)
    }
    
    0 讨论(0)
  • 2021-01-31 04:47

    Have a look at this class I wrote:

    https://github.com/mindplay-dk/jsonfreeze/blob/master/mindplay/jsonfreeze/JsonSerializer.php

    It reserves a JSON object-property named '#type' to store the class-name, and it has some limitations that are described here:

    Serialize/unserialize PHP object-graph to JSON

    0 讨论(0)
  • 2021-01-31 04:47

    To answer your direct question, no, there's no was to do this with json_encode/json_decode. JSON was designed and specified to be a format for encoding information, and not for serializing objects. The PHP function don't go beyond that.

    If you're interested in recreating objects from JSON, one possible solution is a static method on all the objects in your hierarchy that accepts a stdClass/string and populates variables that looks something like this

    //semi pseudo code, not tested
    static public function createFromJson($json){
        //if you pass in a string, decode it to an object
        $json = is_string($json) ? json_decode($json) : $json;
    
        foreach($json as $key=>$value){
            $object = new self();
            if(is_object($value)){
                $object->{$key} = parent::createFromJson($json);
            }
            else{
                $object->{$key} = $value;
            }
        }
    
        return $object;
    }
    

    I didn't test that, but I hope it gets the idea across. Ideally, all your objects should extend from some base object (usually named "class Object") so you can add this code in one place only.

    0 讨论(0)
  • 2021-01-31 04:51

    Bit late but another option is to use symfony serializer to deserialize xml, json, whatever to Object.

    here is documentation: http://symfony.com/doc/current/components/serializer.html#deserializing-in-an-existing-object

    0 讨论(0)
  • 2021-01-31 04:51

    I must say I am a bit dismayed that this isn't just standard, off the shelf functionality -- of some library, if not JSON itself. Why wouldn't you want to have essentially similar objects on both sides? (As far as JSON will let you, anyway)

    Am I missing something here? Is there a library that does this? (AFAICT, none of [thrift, protocol buffers, avro] actually have API's for javascript. For my problem, I am most interested in JS <-> PHP, somewhat also in JS <-> python .)

    0 讨论(0)
  • 2021-01-31 04:58

    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.

    0 讨论(0)
提交回复
热议问题