rfc:jsonable

Request for Comments: Jsonable interface

Introduction

The current state of JSON support in PHP deals with all scalar types smoothly. However, complex data structures cannot be handled by PHP API. This proposal wants to describe a clean way to include this support via implementation of an interface.

Motivation

Consider this piece of code:

class Person
{
    public $name;
    protected $age;
    private $salary;
 
    public function __construct($name, $age, $salary)
    {
        $this->name = $name;
        $this->age = $age;
        $this->salary = $salary;
    }
 
    // ...
}
 
$person = new \Person('Jesus Christ', 32, 10000);
 
echo json_encode($person);

PHP is able to convert public variables, so the return of this script will be:

{"name": "Jesus Christ"}

However, we may want json_(encode|decode) to also export/import protected and private information.

The problem that arrises

PHP json_decode is unable to recognize which class it is meant to be. Two solutions come to our hands:

* Drop json_decode reversal functionality. This is not an optimal solution, since we want to keep both json_encode and json_decode compatibility * Append some reverse engineer information allowing PHP to recognize what class it is.

The second solution can be fixed by attaching a CLASS information to JSON data. Taking our previous example (aswell as the expected behavior), it would generate:

{"__CLASS__": "Person", "name": "Jesus Christ", "age": 32, "salary": 10000}

Including export information is not ideal since it would actually be equal to the Serializable support.

Proposal

A non-intrusive solution should be smooth just like SPL Serializable interface.

interface Jsonable
{
    public function __toJson();
}

It is well known that at this stage, any developer is able to write a piece of code (a method) like the following one to include a similar support:

class Person implements Jsonable
{
    public function __toJson()
    {
        $str = '{"__CLASS__": "' . get_class($this) . '"';
 
        $reflClass = new \ReflectionClass($this);
 
        foreach ($reflClass->getProperties() as $reflProperty) {
            $reflProperty->setAccessible(true);
            $value = $reflProperty->getValue($this);
 
            $str .= ', ' . json_encode($reflProperty->getName()) . ': ';
 
            if (is_object($value) && $value instanceof Jsonable) {
                $str .= $value->__toJson();
            } else if ( ! is_resource($value)) {
                $str .= json_encode($value);
            }
        }
 
        $str .= '}';
 
        return $str;
    }
}

By implementing natively Jsonable, it would be simply necessary to:

class Person
{
    // ...
 
    public function __toJson()
    {
        return array('name', 'age', 'salary');
    }
}

It would be even possible to add custom export support, example:

class Person
{
    // ...
 
    public function __toJson()
    {
        return array('salary');
    }
}

Patch

Currently there's no patch related to this RFC.

Changelog

2010-03-14 Guilherme Blanco: Initial creation.

rfc/jsonable.txt · Last modified: 2014/04/09 00:55 by levim