• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • JsonSerializable类

    (PHP 5 >= 5.4.0, PHP 7)

    实现JsonSerializable的类可以在json_encode()时定制他们的 JSON 表示法。

    JsonSerializable 
    {
    	/* 方法 */
    	abstract public jsonSerialize ( void ) : mixed
    }
    

    JsonSerializable::jsonSerialize

    (PHP 5 >= 5.4.0, PHP 7)

    指定需要被序列化成 JSON 的数据

    说明

    abstractpublicJsonSerializable::jsonSerialize (void) : mixed

    序列化物体(Object)成能被 json_encode() 原生地序列化的值。

    返回值

    返回能被 json_encode() 序列化的数据, 这个值可以是除了 resource 外的任意类型。

    范例

    JsonSerializable::jsonSerialize() 例子 returning an array

    <?php
    class ArrayValue implements JsonSerializable {
        public function __construct(array $array) {
            $this->array = $array;
        }
        public function jsonSerialize() {
            return $this->array;
        }
    }
    $array = [1, 2, 3];
    echo json_encode(new ArrayValue($array), JSON_PRETTY_PRINT);
    ?>
    

    以上例程会输出:

    [
        1,
        2,
        3
    ]
    

    JsonSerializable::jsonSerialize() 例子 返回了一个关联数组 array

    <?php
    class ArrayValue implements JsonSerializable {
        public function __construct(array $array) {
            $this->array = $array;
        }
        public function jsonSerialize() {
            return $this->array;
        }
    }
    $array = ['foo' => 'bar', 'quux' => 'baz'];
    echo json_encode(new ArrayValue($array), JSON_PRETTY_PRINT);
    ?>
    

    以上例程会输出:

    {
        "foo": "bar",
        "quux": "baz"
    }
    

    JsonSerializable::jsonSerialize() 例子 返回一个 integer

    <?php
    class IntegerValue implements JsonSerializable {
        public function __construct($number) {
            $this->number = (integer) $number;
        }
        public function jsonSerialize() {
            return $this->number;
        }
    }
    echo json_encode(new IntegerValue(1), JSON_PRETTY_PRINT);
    ?>
    

    以上例程会输出:

    1
    

    JsonSerializable::jsonSerialize() 例子 返回一个 string

    <?php
    class StringValue implements JsonSerializable {
        public function __construct($string) {
            $this->string = (string) $string;
        }
        public function jsonSerialize() {
            return $this->string;
        }
    }
    echo json_encode(new StringValue('Hello!'), JSON_PRETTY_PRINT);
    ?>
    

    以上例程会输出:

    "Hello!"
    
    A good example on when you would use functionality like this is when working with objects.
    json_encode() will take a DateTime and convert it to:
    {
      "date":"2013-01-31 11:14:05",
      "timezone_type":3,
      "timezone":"America\/Los_Angeles"
    }
    This is great when working with PHP, but if the Date is being read by Java. The Java date parser doesn't know what to do with that. But it does know what to do with the ISO8601 format...
    <?php
    date_default_timezone_set('America/Los_Angeles');
    class Fruit implements JsonSerializable {
      public
        $type = 'Apple',
        $lastEaten = null;
      public function __construct() {
        $this->lastEaten = new DateTime();
      }
      public function jsonSerialize() {
        return [
          'type' => $this->type,
          'lastEaten' => $this->lastEaten->format(DateTime::ISO8601)
        ];
      }
    }
    echo json_encode(new Fruit()); //which outputs: {"type":"Apple","lastEaten":"2013-01-31T11:17:07-0500"}
    ?>
    
    Nested json serializable objects will be serialized recursively. No need to call ->jsonSerialize() on your own. It is especially useful in collections.
    <?php
    class NestedSerializable implements \JsonSerializable
    {
      private $serializable;
      public function __construct($serializable)
      {
        $this->serializable = $serializable;
      }
      public function jsonSerialize()
      {
        return [
          'serialized' => $this->serializable
        ];
      }
    }
    class SerializableCollection implements \JsonSerializable {
      private $elements;
      public function __construct(array $elements)
      {
        $this->elements = $elements;
      }
      public function jsonSerialize()
      {
        return $this->elements;
      }
    }
    // Outputs: [{"serialized":null},{"serialized":null},{"serialized":{"serialized":null}}]
    echo json_encode(
      new SerializableCollection([
        new NestedSerializable(null),
        new NestedSerializable(null),
        new NestedSerializable(new NestedSerializable(null))
      ])
    );
    ?>
    
    Here's a small test/proof that makes it easy to see some comparative results. Null was the one I was interested in since it was not documented:
    <?php
    class jsontest implements JsonSerializable {
        function __construct($value) { $this->value = $value; }
        function jsonSerialize() { return $this->value; }
    }
    print "Null -> " . json_encode(new jsontest(null)) . "\n";
    print "Array -> " . json_encode(new jsontest(Array(1,2,3))) . "\n";
    print "Assoc. -> " . json_encode(new jsontest(Array('a'=>1,'b'=>3,'c'=>4))) . "\n";
    print "Int -> " . json_encode(new jsontest(5)) . "\n";
    print "String -> " . json_encode(new jsontest('Hello, World!')) . "\n";
    print "Object -> " . json_encode(new jsontest((object) Array('a'=>1,'b'=>3,'c'=>4))) . "\n";
    ?>
    Output is:
    Null -> null
    Array -> [1,2,3]
    Assoc. -> {"a":1,"b":3,"c":4}
    Int -> 5
    String -> "Hello, World!"
    Object -> {"a":1,"b":3,"c":4}
    simonsimcity at gmail dot com is wrong, you can throw exceptions in this but it will wrap with another exception so his example outputs
     PHP Fatal error: Uncaught exception 'RuntimeException' with message 'It failed!' in -:8
     Stack trace:
     #0 [internal function]: Foo->jsonSerialize()
     #1 -(16): json_encode(Object(Foo))
     #2 {main}
     Next exception 'Exception' with message 'Failed calling Foo::jsonSerialize()' in -:16
     Stack trace:
     #0 -(0): json_encode()
     #1 {main}
      thrown in - on line 16
    PHP 5.4.39
    For those who are also lazy. You cannot just include $this and expect it to work.
    For example, this won't work:
    <?php
    class SomeClass implements JsonSerializable {
     
      protected $partner;
      function setPartner(object $partner) {
        $this->partner;
      }
      public function jsonSerialize() {
        return $this;
      }
    }
    $foo = new SomeClass();
    $too = new stdClass();
    $too->test = 1;
    $foo->setPartner = $too;
    echo json_encode($foo); // Shows a blank object "{}"
    ?>
    You have to define the things manually, so this will work.
    <?php
    class SomeClass implements JsonSerializable {
     
      protected $partner;
      function setPartner(object $partner) {
        $this->partner;
      }
      public function jsonSerialize() {
        $data['partner'] = $this->partner;
        return $data;
      }
    }
    $foo = new SomeClass();
    $too = new stdClass();
    $too->test = 1;
    $foo->setPartner = $too;
    echo json_encode($foo); // Shows {"partner":{"test":1}}
    Serialize private attributes to JSON in PHP 5.3
    <?php
    abstract class Model {
      public function jsonSerialize() {
        $getter_names = get_class_methods(get_class($this));
        $gettable_attributes = array();
        foreach ($getter_names as $key => $value) {
          if(substr($value, 0, 4) === 'get_') {
            $gettable_attributes[substr($value, 4, strlen($value))] = $this->$value();
          }
        }
        return $gettable_attributes;
      }
    }
    class Content extends Model {
      
      private $title;
      private $text;
      public function get_title() {
        return $this->title;
      }
      public function set_title($title) {
        $this->title = $title;
      }
      public function get_text() {
        return $this->text;
      }
      public function set_text($text) {
        $this->text = $text;
      }
      
    }
    $content = new Content();
    $content->set_title('lol');
    $content->set_text('haha');
    echo json_encode($content->jsonSerialize());
    ?>
    
    You can't throw exceptions in here. If you do, you'll get an exception with the message "Failed calling FooClass::jsonSerialize()" and the stacktrace will start at where you called the json_encode() method.
    Here's a code-example:
    class Foo implements JsonSerializable {
      private $triggerError = true;
      public function jsonSerialize()
      {
        if ($this->triggerError) {
          throw new RuntimeException("It failed!");
        }
        return (array)$this;
      }
    }
    // Will throw an exception like new Exception("Failed calling Foo::jsonSerialize()")
    json_encode(new Foo());
    simple functions to make life easier.
    I wanted a way to have a as property value the return value of a method in order to have it initialized. example
    class portItem implements JsonSerializable{
      private $idPort;
      private $location;
      private $portLanguages;
      public function getLocation() {
        if(!isset($this->location)){
          return new locationItem();
        }
        return $this->location;
      }
      public function setLocation($location) {
        $this->location = $location;
      }
       public function setidPort($idPort){
        $this->idPort=$idPort;
      }
      
      public function getidPort(){
        if(!isset($this->idPort)){
          return 0;
        }
        return intval($this->idPort);
      }
      public function setPortLanguages($portLanguages){
        $this->portLanguages=$portLanguages;
      }
      
      public function getPortLanguages(){
        if(!isset($this->portLanguages)){
          return new genericItems();
        }
        return $this->portLanguages;
      }
      
      public function getCategoryLanguages(){
        if(!isset($this->portLanguages)){
          return new genericItems();
        }
        return $this->portLanguages;
      }
      
      public function getPortLanguageAtIndex($index=false){
        if(!$index){
          $index=0;
        }
        return $this->portLanguages[$index];
      }
      
      public function setPortLanguageAtIndex($index,$language){
        $this->portLanguages[$index]=$language;
      }
        public function jsonSerialize() {
        $dataConverter = new dataConverter();
        return $dataConverter->convertToJson($this);
      }
    }
    Wit 2 ways you can automatically convert for json.
    1.by reading properties
    public function convertToJson($object){
        /*approch by using object properties*/
        $class = get_class($this);
        $json = array();
        $properties = get_class_vars($class);
        $keys = array_keys($properties);
        $plength = count($keys);
        for($i=0;$i<$plength;$i++){
          $method = "get".$keys[$i];
          if(method_exists ($this,$method)){
            $json[$keys[$i]] = $this->$method();
          }
        }
    return $json;
    }
    public function convertToJson($object){   
    /*approch by using object methods*/
        $class = get_class($object);
        $json = array();
        $methods = get_class_methods($class);
        $plength = count($methods);
        $json = array();
        for($i=0;$i<$plength;$i++){
          if(stripos($methods[$i], "get")!==FALSE){
            $property = mb_substr($methods[$i], 3,mb_strlen($methods[$i],'UTF-8'),'UTF-8');
            $setter = "set".mb_substr($methods[$i], 3,mb_strlen($methods[$i],'UTF-8'),'UTF-8');
            if(method_exists($object,$setter)){
              $json[$property] = $object->$methods[$i]();
            }
            
          }
        }
        
        return $json;
      }
    By using this method the result will be a json with value for properties initialized according to each method. 
    Things to note
    1.if you are using the reading properties approach the code cant' work outside of the class for private properties, because they are nto visible, you have to put it the code directly to public function jsonSerialize() {} in order to work.
    2.For both approaches has method seems not to be case sensitive else you are going to have problems, i strongly suggest to pay attention in naming convention between property names and method names idPort =>setIdPort() =>getIdPort() (i know my class is done not that way).
    3.both approaches since you call method without knowing the arguments you need to pay attention in arguments for getter methods where applicable, check my example 
    public function getPortLanguageAtIndex($index=false){
        if(!$index){
          $index=0;
        }
        return $this->portLanguages[$index];
      }
    that's why i have set it to optional argument. If you don't do that php will complain about missing argument parameter in method XXX.

    下篇:json_decode()