JSON is the format I use the most when it comes to data transfer. In almost every case I serialize my date with json_encode and at some point in time I use json_decode to get the data back into a somehow structured format.

For example I’m trying to encode/decode a class called Person. The encoding part is easy, add the JsonSerializable interface to the model and implement the JsonSerialize method, call json_encode on a model instance and you are done.

But the decoding confronts me with the same issue everytime I need to decode JSON data. json_decode returns the decoded data in an object of type stdClass or if you use the assoc parameter the data gets stored in an array.

In most situations both approaches are not useful because you need objects with the initial type (especially if you are using PHP7 type hints ❤️️).

To solve this issue I implement some sort of conversion everytime I’m trying to decode data back into its original model. A few weeks ago I was hacked of to do this sh** again and I decided to write a PHP package called json-decoder.

The basic idea

The package should provide me with an easy mechanism to transform JSON into a PHP model instance. For the standard case (json field name equals property name) no further configuration should be necessary and if I want to transform a more complex type I should be able to define a Tranformer for it.

A simple example

Let’s reuse the mentioned Person class from above.

class Person {
    public $firstname;
    public $lastname;
}

The JSON data will look like this:

{
    "firstname": "John",
    "lastname": "Doe"
}

To tranform the data into an instance of Person the following 3 lines of code are necessary:

$jsonDecoder = new JsonDecoder();
$jsonData = '{"firstname": "John", "lastname": "Doe"}';

$person = $jsonDecoder->decode($jsonData, Person::class);

Using a transformer

Tranformers are necessary to define data types of a nested property. For example the Person class has a field called address which is of type Address.

The basic example above would add the JSON data as an array to the address field. To get the correct type you can define a so called Transformer:

class PersonTransformer implements Transformer {

    public function register(ClassBindings $classBindings)
    {
        $classBindings->register(new FieldBinding('address', 'address', Address::class);
    }

    public function transforms()
    {
        return Person::class;
    }
}

The Transformer interface defines two methods for registering your field bindings and also for the information which class type it can transform.

As you can see the standard case from the basic example gets also handled out of the box, that means no configuration for the firstname and lastname fields are necessary.

Conclusion

I’ve now used the package in two of my latest projects and I’m quite happy with the implementation. In the next time I’m going to add some small improvements to the code and also install the CI pipeline on the project. I think this package is interesting for many people so please help me to get it out and known to them by spreading the word.

Resources