DEV Community

Cover image for Don't call jsonSerialize() explicitly
Quentin Delcourt
Quentin Delcourt

Posted on • Originally published at quentin.delcourt.be

Don't call jsonSerialize() explicitly

TL;DR don't call jsonSerialize() directly, always pass the object implementing it to the json_encode function.

JsonSerializable is a handy PHP feature that was introduced in PHP 5.4.
It lets you define how an object should be transformed into JSON when passed to the json_encode function.
For example, if you were to order a box of chocolate and send a preview of it to someone you offer it to,
you might want to show the content of the box but not its price.

By defining an array of properties (but the return value could be anything that could be serialized to JSON), you get to decide what information will be returned in the resulting JSON:

final class ChocolateBox implements JsonSerializable
{
    private int $price;
    private array $chocolates;

    /* Magic code to build the box... */

    public function jsonSerialize() : array
    {
        return [
            'chocolates' => $this->chocolates,
        ];
    }
}

So far, so good.
And then, in the client, usually a controller, I sometimes see this:

final class ChocolateBoxController
{
    public function indexAction(Request $request, ChocolateBoxService $chocolateBoxService) : Response
    {
        $chocolateBox = $chocolateBoxService->getRandomBox();

        return new Response(
            json_encode($chocolateBox->jsonSerialize())
        );
    }
}

👆 Can you spot the problem in the code above?

We're calling json_encode and passing it the result of the jsonSerialize method.
That's not the idea... json_encode actually knows about the existence of the function if the object it's being passed
implements the JsonSerializable interface.

Therefore, simply passing the object to json_encode is enough:

json_encode($chocolateBox)

👇 gives us

{
    "chocolates" => [/* delicious list of chocolates */]
}

It even works when you bury the object in another structure, such as an array:

json_encode([
    'data' => $chocolateBox,
])

👇 gives us

{
    "data": {
        "chocolates" => [/* delicious list of chocolates */]
    }
}

By implementing the interface you allow json_encode to get what it needs out of an object.
Your work stops right after that, let json_encode do the rest...


Originally published on quentin.delcourt.be

Top comments (0)