sajad torkamani

What is deserialization?

Deserialization is the process of converting a data string in a format like JSON or XML into a PHP object. It involves first decoding the data string into a PHP array and then denormalizing the array into a PHP object. Deserialization is the opposite of serialization.

Deserialization plays an essential part in building web services / REST APIs because you must be able to convert application-specific data types (e.g., a Customer or PolicyQuote PHP object) into a format (usually JSON) that can be easily consumed by clients or other web services.

Deserialize data into a PHP object using Symfony Serializer

How to deserialize

Install dependencies

Install the Serializer component:

composer require symfony/serializer

Assuming you’ll use the ObjectNormalizer as your normalizer, install the PropertyAccess component that it depends on:

composer require symfony/property-access

Use serializer

Instantiate a serializer that implements the SerializerInterface and call its deserialize method which takes three arguments:

  1. The data (as a string) to be decoded (e.g., XML, JSON, etc).
  2. The name of the class to decoded the data to.
  3. The encoder to use to convert the data into a PHP array.
<?php

// src/deserialize.php

use App\Entity\Person;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

require 'vendor/autoload.php';

$encoders = [new XmlEncoder(), new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);

$data = <<<EOF
<person>
    <name>Sajad</name>
    <age>28</age>
    <isAlive>true</isAlive>
</person>
EOF;

$person = $serializer->deserialize($data, Person::class, 'xml');

dump($person);

Running this should output:

App\Entity\Person {#18php 
  -age: "28"
  -name: "Sajad"
  -isAlive: true
}

Handle additional attributes that don’t have a 1-1 mapping

By default, additional attributes that don’t map to the denormalized object will be ignored by the Serializer component. So, if in the example above, we had a <gender>Male</gender> XML attribute but there was no corresponding $gender property in the Person class, the Serializer component would silently ignore <gender>.

You can instead choose to throw an exception when an unrecognized attribute is given:

use App\Model\Person;

$data = <<<EOF
<person>
    <name>Sajad</name>
    <age>28</age>
    <isAlive>true</isAlive>
    <gender>Male</gender>
</person>
EOF;

$classMetadataFactory = new ClassMetadataFactory($loader);
$normalizer = new ObjectNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer]);

// this will throw a Symfony\Component\Serializer\Exception\ExtraAttributesException
// because "city" is not an attribute of the Person class
$person = $serializer->deserialize($data, Person::class, 'xml', [
    AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
]);

Deserialize into an existing object

You can also deserialize data into an existing object:

// ...
$person = new Person();
$person->setName('bar');
$person->setAge(99);
$person->setSportsperson(true);

$data = <<<EOF
<person>
    <name>foo</name>
    <age>69</age>
</person>
EOF;

$serializer->deserialize($data, Person::class, 'xml', [AbstractNormalizer::OBJECT_TO_POPULATE => $person]);
// $person = App\Model\Person(name: 'foo', age: '69', sportsperson: true)

This is a common use case when working with Doctrine ORM. For example, if a client makes a PATCH request to update an existing resource, you’ll typically load an entity first and deserialize the incoming data into the entity.

Sources

Tagged: Symfony