SpraySerializer
Fast and easy serialization and deserialization of php objects., (*1)
, (*2)
Internals
Serialization is performed by attaching to a specific class scope using the Closure::bind method. To keep things fast, reflection is only used while generating the serialization code., (*3)
How to use
Let's start with a class to serialize. Note that the annotations hint the serializer, and that they're required for deserializing objects., (*4)
/**
* Person
*/
class Person
{
/**
* @var string
*/
private $name;
/**
* @var Address
*/
private $address;
public function __construct($name, Address $address)
{
$this->name = (string) $name;
$this->address = $address;
}
}
/**
* Address
*/
class Address
{
/**
* @var string
*/
private $street;
public function __construct($street)
{
$this->street = (string) $street;
}
}
Then we'll initialize the serializer., (*5)
$serializer = new Serializer();
$serializer->attach(
new ObjectListener(
new SerializerLocator(
new SerializerRegistry(),
new ObjectSerializerGenerator(
new AnnotationBackedPropertyInfo()
),
new ArrayCache('Serializer')
)
)
);
Now we can serialize almost any object to an array and back to an object., (*6)
$data = $serializer->serialize(new Person('Name', new Address('Street')));
var_dump($data);
// array(2) {
// 'name' =>
// string(4) "Name"
// 'address' =>
// array(1) {
// 'street' =>
// string(6) "Street"
// }
// }
$object = $serializer->deserialize('Person', $data);
var_dump($object);
// class Person#8 (2) {
// private $name =>
// string(4) "Name"
// private $address =>
// class Address#18 (1) {
// private $street =>
// string(6) "Street"
// }
// }
As the example above shows, the serializer uses default docblock annotations to determine the serialization strategy. The following annotations are supported:, (*7)
class SerializeMe
{
/**
* @var string
*/
private $string;
/**
* @var int
*/
private $int;
/**
* @var integer
*/
private $integer;
/**
* @var bool
*/
private $bool;
/**
* @var boolean
*/
private $boolean;
/**
* @var float
*/
private $float;
/**
* @var double
*/
private $double;
/**
* @var array
*/
private $array;
/**
* @var Object
*/
private $object;
/**
* @var string[]
*/
private $stringArray;
/**
* @var Object[]
*/
private $objectArray;
/**
* @var array<string>
*/
private $stringArrayJavaStyle;
/**
* @var array<Object>
*/
private $objectArrayJavaStyle;
}
There're some limitations to the implemented serialization method. For instance,
deserializing a DateTime(Immutable) object is not possible. For this reason,
specialized serializers are added. You'll need to add these to the
SerializerRegistry in your application bootstrap like so:, (*8)
$registry = new SerializerRegistry();
$registry->add(new DateTimeSerializer());
$registry->add(new DateTimeImmutableSerializer());
$registry->add(new StdClassSerializer());
$serializer = new Serializer();
$serializer->attach(
new ObjectListener(
new SerializerLocator(
$registry,
new ObjectSerializerGenerator(
new AnnotationBackedPropertyInfo()
),
new ArrayCache('Serializer')
)
)
);
In order to support object inheritance (de)serialization, just the annotations is not enough. The ObjectTypeListener is required to enable this functionality:, (*9)
$serializer = new Serializer();
$serializer->attach(
new ObjectTypeListener()
);
$serializer->attach(
new ObjectListener(
new SerializerLocator(
new SerializerRegistry(),
new ObjectSerializerGenerator(
new AnnotationBackedPropertyInfo()
),
new ArrayCache('Serializer')
)
)
);
Note: Enabling this feature results in your data populated with '__type' => 'ClassName'., (*10)
When your application requires encryption you'll have to attach the EncryptionListener:, (*11)
$blockCipher = BlockCipher::factory('mcrypt', ['algo' => 'aes']);
$blockCipher->setKey('5eDCZRmyX8s7nbgV9f6pVrmRISdc5t8L');
$serializer = new Serializer();
$serializer->attach(
new EncryptionListener(
new EncryptorLocator(
new EncryptorGenerator(new AnnotationBackedPropertyInfo()),
new ArrayCache('Encryptor')
),
$blockCipher
)
);
$serializer->attach(
new ObjectListener(
new SerializerLocator(
new SerializerRegistry(),
new ObjectSerializerGenerator(
new AnnotationBackedPropertyInfo()
),
new ArrayCache('Serializer')
)
)
);
The library provides two methods of caching: array and file. The array cache is
primarily useful for testing/development purposes. For production however, you're
better off using the FileCache., (*12)
The file cache actually writes the generated serialization code to plain php
files for later use (and therefore automatically cached in op-code cache)., (*13)
Below is how you'd bootstrap the file cache for the serializer:, (*14)
use Symfony\Component\Filesystem\Filesystem;
$serializer = new Serializer();
$serializer->attach(
new ObjectListener(
new SerializerLocator(
new SerializerRegistry(),
new ObjectSerializerGenerator(
new AnnotationBackedPropertyInfo()
),
new FileCache(new Filesystem(), '/path/to/cache/directory', 'Serializer')
)
)
);