Serializing PHP objects into JSON with JsonSerializable

August 29, 2012 | 3 comments

JSON (JavaScript Object Notation) is a handy data interchange format that’s overtaken XML in a very short time for a lot of API use cases – and rightly so. It’s easy to use, bandwidth efficient, and widely supported across platforms and languages.

PHP is still one of the most widely-used web scripting languages. It’s perhaps not as cool as Python or Ruby on Rails, but it’s got its adherents. I’m still a fan, although there are some things – like long-polling real-time sites – that are much harder to do on the platform. And when it comes to JSON, it doesn’t get any easier than $json_string = json_encode($php_data); and $php_data = json_decode($json_string);. (Assuming you have the PHP JSON module compiled and enabled – but if you’re using PHP 5.2 or above, you probably do.)

Unfortunately, if you’re using object orientated code and your data to encode includes an object, json_encode() has traditionally not been as friendly as it might have been. Sometimes, for example, you want to define exactly how your objects translate to JSON, to avoid lost data (or too much data). This is particularly true if you’re using magic methods to get and set properties, as I often do.

PHP 5.4 contains a new interface, JsonSerializable, that gives you this control. Once you add the interface to your class:

class myClass implements JsonSerializable {
    // ...

You can add a new function, jsonSerialize, that will be triggered whenever json_encode() is run on the object, and returns the PHP data of your choice:

class myClass implements JsonSerializable {
    // ...
    function jsonSerialize() {
        $data = array();
        // Represent your object using a nested array or stdClass,
        // in the way you want it arranged in your API
        return $data;

Now, when you run json_encode() over a data structure that includes your objects, you’ll know that they’re being saved in a way that can easily be interpreted by your API consumers. Again, the function should return PHP data that can be serialized by json_encode(), rather than encoded JSON data. I recommend using nested arrays, or a stdClass object, for simplicity.

Note that unlike, say, serialize() (which serializes data in a PHP-specific format), this isn’t a two-way translation. In other words, json_decode() won’t automatically reconstitute your object with class from your data.

We can illustrate that by taking the following test class (which I’ll expand first and then print the var_export() output for):

class TestClass {
    public $foo = 'bar';
    public $dev = 'null';
TestClass::__set_state(array( 'foo' => 'bar', 'dev' => 'null', ))

Which json_encode() encodes as:


(Because that was a simple object, there was no need to employ jsonSerialize() in its construction.)

In turn, the JSON string is decoded back into PHP as:

stdClass::__set_state(array( 'foo' => 'bar', 'dev' => 'null', ))

Note that the classname has vanished and the class is reduced to being a stdClass. As a result, you need to take care when consuming JSON data and turning it back into your internal data structures – which is a very good idea anyway. It’s perhaps worth creating your own validator function that can take in a stdClass object and, following sanity checking and sanitization, turn it back into one of your own classes.

And that’s it. I don’t normally write about code here, so please let me know if you found this useful.