symfony/serializer
Symfony Serializer component for converting objects and complex data structures to/from arrays, JSON, XML and more. Supports object graphs, custom normalizers/encoders, and flexible context options for reliable serialization and deserialization.
Install via Composer:
composer require symfony/serializer
First Use Case: Serializing an Eloquent Model to JSON
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
// In a service or controller
$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);
$user = User::find(1);
$json = $serializer->serialize($user, 'json');
First Use Case: Deserializing JSON to a Model
$data = json_decode('{"name":"John","email":"john@example.com"}', true);
$user = $serializer->deserialize($data, User::class, 'array');
ObjectNormalizer – Handles basic object-to-array conversion (most commonly used).Serializer class – The main entry point for serialization/deserialization.Encoder interfaces – For format-specific handling (e.g., JsonEncoder, XmlEncoder).// Serialize to JSON
$json = $serializer->serialize($object, 'json');
// Deserialize from JSON
$object = $serializer->deserialize($json, stdClass::class, 'json');
Leverage ObjectNormalizer with ignoredAttributes or circularReferenceHandler:
$normalizer = new ObjectNormalizer(null, null, null, [
'ignoredAttributes' => ['password', 'apiToken'],
'circularReferenceHandler' => function ($object) {
return 'REF_' . spl_object_hash($object);
}
]);
Extend ObjectNormalizer or create a custom normalizer for domain-specific logic:
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class UserNormalizer implements NormalizerInterface
{
public function normalize($object, string $format = null, array $context = [])
{
return [
'id' => $object->id,
'name' => $object->name,
'email' => $object->email,
'role' => $object->role->value, // Handle relationships
];
}
public function supportsNormalization($data, string $format = null): bool
{
return $data instanceof User;
}
}
Use @Groups annotations or context-based filtering:
// In User entity
use Symfony\Component\Serializer\Annotation\Groups;
class User
{
#[Groups(['api:read'])]
public string $name;
#[Groups(['api:write'])]
public string $email;
}
// Serialize with groups
$serializer->serialize($user, 'json', [
AbstractNormalizer::GROUPS => ['api:read']
]);
Combine with Symfony’s Validator for strict deserialization:
use Symfony\Component\Validator\Validator\ValidatorInterface;
$validator = app(ValidatorInterface::class);
$errors = $validator->validate($deserializedObject);
if ($errors->count() > 0) {
throw new \RuntimeException('Validation failed');
}
Configure DateTimeNormalizer for consistent formatting:
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
$normalizers = [
new DateTimeNormalizer(),
new ObjectNormalizer(),
];
$serializer = new Serializer($normalizers, $encoders);
Use denormalize() with partial data:
$data = ['name' => 'Updated Name'];
$user = $serializer->deserialize($data, User::class, 'array', [
AbstractNormalizer::OBJECT_TO_POPULATE => $existingUser,
]);
Service Provider Binding
Bind the serializer in AppServiceProvider for global access:
public function register()
{
$this->app->singleton(SerializerInterface::class, function () {
$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
return new Serializer($normalizers, $encoders);
});
}
API Resource Integration
Use in Illuminate\Http\Resources\Json\JsonResource:
public function toArray($request)
{
return $this->serializer->normalize($this->resource, null, [
AbstractNormalizer::GROUPS => ['api'],
]);
}
Form Request Validation Deserialize and validate incoming requests:
public function rules()
{
$data = $this->serializer->deserialize(
$this->request->json()->all(),
stdClass::class,
'array'
);
return [
'name' => 'required|string',
'email' => 'required|email',
];
}
Queue Jobs Serialize payloads for delayed processing:
$serializedData = $serializer->serialize($payload, 'json');
dispatch(new ProcessPayloadJob($serializedData));
Circular References
User ↔ Post).circularReferenceHandler in ObjectNormalizer or implement a custom handler.Type Mismatches in Deserialization
int vs. string).$normalizer = new ObjectNormalizer(null, null, null, [
'constructor_parameters' => [
'id' => ['type' => 'int', 'default' => null],
],
]);
Ignored Attributes
password) leaking into serialized output.$normalizer = new ObjectNormalizer(null, null, null, [
'ignoredAttributes' => ['password', 'api_token'],
]);
DateTime Handling
DateTime objects.DateTimeNormalizer:
$dateNormalizer = new DateTimeNormalizer('UTC');
Partial Deserialization
OBJECT_TO_POPULATE context:
$serializer->deserialize($data, User::class, 'array', [
AbstractNormalizer::OBJECT_TO_POPULATE => $user,
]);
Custom Metadata Overrides
property_type_extractor or method_name_converter:
$normalizer = new ObjectNormalizer(null, null, null, [
'property_type_extractor' => new PhpDocTypeExtractor(),
]);
Enable Debug Mode
Set debug: true in ObjectNormalizer to log normalization issues:
$normalizer = new ObjectNormalizer(null, null, null, ['debug' => true]);
Inspect Normalization Groups
Use AbstractNormalizer::GROUPS to debug which fields are included/excluded:
$serializer->serialize($object, 'json', [
AbstractNormalizer::GROUPS => ['debug:all'],
]);
Check for Deprecated Methods
normalize() in favor of serialize()/deserialize().Handle Undefined Properties
__get()/__set() magic methods causing unexpected behavior.ObjectNormalizer to handle magic properties:
$normalizer = new ObjectNormalizer(null, null, null, [
'allow_magic_properties' => true,
]);
Custom Normalizers
Implement NormalizerInterface for domain-specific logic (e.g., hashing passwords, flattening nested objects).
Custom Encoders
Extend EncoderInterface to support new
How can I help you explore Laravel packages today?