Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Symfony Serializer
https://github.com/symfony/serializer
Admin
Symfony Serializer is a component for serializing and deserializing complex data structures and
...
Tokens:
8,753
Snippets:
34
Trust Score:
9.2
Update:
1 month ago
Context
Skills
Chat
Benchmark
83
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Symfony Serializer The Symfony Serializer component is a powerful PHP library for converting complex data structures and object graphs into various formats including JSON, XML, CSV, and YAML, and vice versa. It provides a two-step process: normalization (converting objects to arrays) and encoding (converting arrays to specific formats), enabling seamless transformation between PHP objects and serialized data. The component supports advanced features including serialization groups for controlling which properties are serialized, name converters for transforming property names between formats, circular reference handling, max depth control, and discriminator maps for polymorphic deserialization. It integrates tightly with Symfony's ecosystem and supports PHP 8 attributes for declarative configuration of serialization behavior. ## Serializer Class The main `Serializer` class provides the entry point for all serialization operations. It combines normalizers and encoders to transform data between PHP objects and serialized formats, supporting multiple output formats and customizable context options. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; // Define a simple class class User { public function __construct( public string $name, public string $email, public \DateTimeInterface $createdAt ) {} } // Create serializer with normalizers and encoders $serializer = new Serializer( [new DateTimeNormalizer(), new ObjectNormalizer()], [new JsonEncoder(), new XmlEncoder()] ); // Create a user object $user = new User('John Doe', 'john@example.com', new \DateTime('2024-01-15')); // Serialize to JSON $json = $serializer->serialize($user, 'json'); // Output: {"name":"John Doe","email":"john@example.com","createdAt":"2024-01-15T00:00:00+00:00"} // Serialize to XML $xml = $serializer->serialize($user, 'xml'); // Output: <?xml version="1.0"?><response><name>John Doe</name><email>john@example.com</email>...</response> // Deserialize JSON back to object $userData = '{"name":"Jane Doe","email":"jane@example.com","createdAt":"2024-02-20T10:30:00+00:00"}'; $deserializedUser = $serializer->deserialize($userData, User::class, 'json'); // $deserializedUser is a User object with the provided data ``` ## ObjectNormalizer The `ObjectNormalizer` is the most versatile normalizer, using the PropertyAccess component to handle objects with public properties, getters/setters, and magic methods. It automatically detects accessible properties and converts them to/from arrays. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; class Product { private string $name; private float $price; private bool $inStock; public function getName(): string { return $this->name; } public function setName(string $name): void { $this->name = $name; } public function getPrice(): float { return $this->price; } public function setPrice(float $price): void { $this->price = $price; } public function isInStock(): bool { return $this->inStock; } public function setInStock(bool $inStock): void { $this->inStock = $inStock; } } $serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]); $product = new Product(); $product->setName('Widget'); $product->setPrice(29.99); $product->setInStock(true); // Serialize - automatically uses getters $json = $serializer->serialize($product, 'json'); // Output: {"name":"Widget","price":29.99,"inStock":true} // Deserialize - automatically uses setters $data = '{"name":"Gadget","price":49.99,"inStock":false}'; $product = $serializer->deserialize($data, Product::class, 'json'); // $product->getName() returns "Gadget" ``` ## Groups Attribute The `#[Groups]` attribute controls which properties are included in serialization based on group names. This enables different representations of the same object for different API endpoints or use cases. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; class Article { #[Groups(['list', 'detail'])] public int $id; #[Groups(['list', 'detail'])] public string $title; #[Groups(['detail'])] public string $content; #[Groups(['admin'])] public string $internalNotes; public function __construct(int $id, string $title, string $content, string $internalNotes) { $this->id = $id; $this->title = $title; $this->content = $content; $this->internalNotes = $internalNotes; } } $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); $serializer = new Serializer( [new ObjectNormalizer($classMetadataFactory)], [new JsonEncoder()] ); $article = new Article(1, 'Hello World', 'Full article content here...', 'Internal review pending'); // Serialize with 'list' group - only id and title $listJson = $serializer->serialize($article, 'json', ['groups' => ['list']]); // Output: {"id":1,"title":"Hello World"} // Serialize with 'detail' group - id, title, and content $detailJson = $serializer->serialize($article, 'json', ['groups' => ['detail']]); // Output: {"id":1,"title":"Hello World","content":"Full article content here..."} // Serialize with multiple groups $adminJson = $serializer->serialize($article, 'json', ['groups' => ['detail', 'admin']]); // Output: {"id":1,"title":"Hello World","content":"Full article content here...","internalNotes":"Internal review pending"} ``` ## SerializedName Attribute The `#[SerializedName]` attribute allows customizing the property name used in the serialized output, enabling compatibility with different naming conventions in external APIs. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Attribute\SerializedName; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; class ApiResponse { #[SerializedName('user_id')] public int $userId; #[SerializedName('first_name')] public string $firstName; #[SerializedName('last_name')] public string $lastName; #[SerializedName('email_address')] public string $emailAddress; public function __construct(int $userId, string $firstName, string $lastName, string $emailAddress) { $this->userId = $userId; $this->firstName = $firstName; $this->lastName = $lastName; $this->emailAddress = $emailAddress; } } $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); $serializer = new Serializer( [new ObjectNormalizer($classMetadataFactory)], [new JsonEncoder()] ); $response = new ApiResponse(42, 'John', 'Doe', 'john.doe@example.com'); // Serialize uses custom names $json = $serializer->serialize($response, 'json'); // Output: {"user_id":42,"first_name":"John","last_name":"Doe","email_address":"john.doe@example.com"} // Deserialize also recognizes custom names $data = '{"user_id":100,"first_name":"Jane","last_name":"Smith","email_address":"jane@example.com"}'; $obj = $serializer->deserialize($data, ApiResponse::class, 'json'); // $obj->userId = 100, $obj->firstName = "Jane" ``` ## CamelCaseToSnakeCaseNameConverter The `CamelCaseToSnakeCaseNameConverter` automatically converts between camelCase PHP property names and snake_case serialized names, useful for API compatibility without individual attribute annotations. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; class UserProfile { public int $userId; public string $firstName; public string $lastName; public string $emailAddress; public \DateTimeInterface $createdAt; public function __construct( int $userId, string $firstName, string $lastName, string $emailAddress, \DateTimeInterface $createdAt ) { $this->userId = $userId; $this->firstName = $firstName; $this->lastName = $lastName; $this->emailAddress = $emailAddress; $this->createdAt = $createdAt; } } $nameConverter = new CamelCaseToSnakeCaseNameConverter(); $serializer = new Serializer( [new ObjectNormalizer(null, $nameConverter)], [new JsonEncoder()] ); $profile = new UserProfile(1, 'John', 'Doe', 'john@example.com', new \DateTime()); // All properties automatically converted to snake_case $json = $serializer->serialize($profile, 'json'); // Output: {"user_id":1,"first_name":"John","last_name":"Doe","email_address":"john@example.com","created_at":"..."} // Deserialize from snake_case back to camelCase properties $data = '{"user_id":2,"first_name":"Jane","last_name":"Smith","email_address":"jane@example.com","created_at":"2024-01-01T00:00:00+00:00"}'; $profile = $serializer->deserialize($data, UserProfile::class, 'json'); // $profile->userId = 2, $profile->firstName = "Jane" ``` ## Ignore Attribute The `#[Ignore]` attribute excludes specific properties from serialization entirely, useful for sensitive data or internal state that should never be exposed. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Attribute\Ignore; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; class Account { public int $id; public string $username; #[Ignore] public string $passwordHash; #[Ignore] public string $securityToken; public string $email; public function __construct(int $id, string $username, string $passwordHash, string $securityToken, string $email) { $this->id = $id; $this->username = $username; $this->passwordHash = $passwordHash; $this->securityToken = $securityToken; $this->email = $email; } } $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); $serializer = new Serializer( [new ObjectNormalizer($classMetadataFactory)], [new JsonEncoder()] ); $account = new Account(1, 'johndoe', 'hashed_password_123', 'secret_token_abc', 'john@example.com'); // Sensitive fields are excluded from serialization $json = $serializer->serialize($account, 'json'); // Output: {"id":1,"username":"johndoe","email":"john@example.com"} // passwordHash and securityToken are NOT included ``` ## MaxDepth Attribute The `#[MaxDepth]` attribute controls how deep the serializer traverses nested objects, preventing infinite loops and controlling output size for deeply nested structures. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Attribute\MaxDepth; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; class Category { public int $id; public string $name; #[MaxDepth(2)] public ?Category $parent = null; /** @var Category[] */ #[MaxDepth(2)] public array $children = []; public function __construct(int $id, string $name) { $this->id = $id; $this->name = $name; } } $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); $serializer = new Serializer( [new ObjectNormalizer($classMetadataFactory)], [new JsonEncoder()] ); // Create nested category structure $root = new Category(1, 'Electronics'); $computers = new Category(2, 'Computers'); $laptops = new Category(3, 'Laptops'); $gaming = new Category(4, 'Gaming Laptops'); $root->children = [$computers]; $computers->parent = $root; $computers->children = [$laptops]; $laptops->parent = $computers; $laptops->children = [$gaming]; $gaming->parent = $laptops; // Enable max depth handling in context $json = $serializer->serialize($root, 'json', [ 'enable_max_depth' => true ]); // Output includes up to 2 levels of nesting, then stops // {"id":1,"name":"Electronics","parent":null,"children":[{"id":2,"name":"Computers",...}]} ``` ## DateTimeNormalizer The `DateTimeNormalizer` handles serialization and deserialization of DateTime objects with customizable format and timezone support. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; class Event { public string $title; public \DateTimeInterface $startDate; public \DateTimeInterface $endDate; public function __construct(string $title, \DateTimeInterface $startDate, \DateTimeInterface $endDate) { $this->title = $title; $this->startDate = $startDate; $this->endDate = $endDate; } } // Default RFC3339 format $serializer = new Serializer( [new DateTimeNormalizer(), new ObjectNormalizer()], [new JsonEncoder()] ); $event = new Event( 'Conference', new \DateTime('2024-06-15 09:00:00'), new \DateTime('2024-06-15 17:00:00') ); $json = $serializer->serialize($event, 'json'); // Output: {"title":"Conference","startDate":"2024-06-15T09:00:00+00:00","endDate":"2024-06-15T17:00:00+00:00"} // Custom date format $customSerializer = new Serializer( [new DateTimeNormalizer([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i']), new ObjectNormalizer()], [new JsonEncoder()] ); $customJson = $customSerializer->serialize($event, 'json'); // Output: {"title":"Conference","startDate":"2024-06-15 09:00","endDate":"2024-06-15 17:00"} // With timezone conversion $tzSerializer = new Serializer( [new DateTimeNormalizer([ DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i T', DateTimeNormalizer::TIMEZONE_KEY => new \DateTimeZone('America/New_York') ]), new ObjectNormalizer()], [new JsonEncoder()] ); ``` ## JsonEncoder The `JsonEncoder` handles JSON encoding and decoding with support for PHP's json_encode/json_decode options through context parameters. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\JsonEncode; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; class Report { public string $title; public array $data; public string $description; } $serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]); $report = new Report(); $report->title = 'Sales Report'; $report->data = ['q1' => 1000, 'q2' => 1500, 'q3' => 1200, 'q4' => 1800]; $report->description = "Annual sales with special chars: <>&\"'"; // Default JSON encoding $json = $serializer->serialize($report, 'json'); // Output: {"title":"Sales Report","data":{"q1":1000,"q2":1500,"q3":1200,"q4":1800},"description":"Annual sales with special chars: <>&\"'"} // Pretty-printed JSON with options $prettyJson = $serializer->serialize($report, 'json', [ JsonEncode::OPTIONS => JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ]); // Output is formatted with indentation // Decode JSON with associative arrays $jsonData = '{"name":"Test","values":[1,2,3]}'; $decoded = $serializer->decode($jsonData, 'json'); // $decoded = ['name' => 'Test', 'values' => [1, 2, 3]] ``` ## XmlEncoder The `XmlEncoder` serializes data to XML format with configurable root node name, CDATA wrapping, and attribute handling. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; class Book { public string $title; public string $author; public int $year; public string $description; } $serializer = new Serializer([new ObjectNormalizer()], [new XmlEncoder()]); $book = new Book(); $book->title = 'The Great Gatsby'; $book->author = 'F. Scott Fitzgerald'; $book->year = 1925; $book->description = 'A story about <wealth> & the American Dream'; // Default XML encoding $xml = $serializer->serialize($book, 'xml'); // Output: <?xml version="1.0"?><response><title>The Great Gatsby</title>...</response> // Custom root node name $xml = $serializer->serialize($book, 'xml', [ XmlEncoder::ROOT_NODE_NAME => 'book' ]); // Output: <?xml version="1.0"?><book><title>The Great Gatsby</title>...</book> // Formatted output with encoding $xml = $serializer->serialize($book, 'xml', [ XmlEncoder::ROOT_NODE_NAME => 'book', XmlEncoder::FORMAT_OUTPUT => true, XmlEncoder::ENCODING => 'UTF-8' ]); // Decode XML to array $xmlData = '<?xml version="1.0"?><book><title>1984</title><author>George Orwell</author></book>'; $decoded = $serializer->decode($xmlData, 'xml'); // $decoded = ['title' => '1984', 'author' => 'George Orwell'] ``` ## CsvEncoder The `CsvEncoder` handles CSV encoding and decoding with support for custom delimiters, headers, and nested data flattening. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\CsvEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; class Employee { public int $id; public string $name; public string $department; public float $salary; } $serializer = new Serializer([new ObjectNormalizer()], [new CsvEncoder()]); $employees = [ ['id' => 1, 'name' => 'John Doe', 'department' => 'Engineering', 'salary' => 75000], ['id' => 2, 'name' => 'Jane Smith', 'department' => 'Marketing', 'salary' => 65000], ['id' => 3, 'name' => 'Bob Wilson', 'department' => 'Engineering', 'salary' => 80000], ]; // Default CSV encoding $csv = $serializer->serialize($employees, 'csv'); // Output: // id,name,department,salary // 1,"John Doe",Engineering,75000 // 2,"Jane Smith",Marketing,65000 // 3,"Bob Wilson",Engineering,80000 // Custom delimiter and enclosure $csv = $serializer->serialize($employees, 'csv', [ CsvEncoder::DELIMITER_KEY => ';', CsvEncoder::ENCLOSURE_KEY => "'", ]); // Output uses semicolons and single quotes // Without headers $csv = $serializer->serialize($employees, 'csv', [ CsvEncoder::NO_HEADERS_KEY => true ]); // Decode CSV $csvData = "id,name,department\n1,Alice,Sales\n2,Bob,IT"; $decoded = $serializer->decode($csvData, 'csv'); // $decoded = [['id' => '1', 'name' => 'Alice', 'department' => 'Sales'], ...] ``` ## YamlEncoder The `YamlEncoder` serializes data to YAML format with configurable inline depth and YAML flags, requiring the symfony/yaml component. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\YamlEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; class Config { public string $environment; public array $database; public array $cache; } $serializer = new Serializer([new ObjectNormalizer()], [new YamlEncoder()]); $config = new Config(); $config->environment = 'production'; $config->database = [ 'host' => 'localhost', 'port' => 5432, 'name' => 'myapp', 'credentials' => ['user' => 'admin', 'password' => 'secret'] ]; $config->cache = ['driver' => 'redis', 'ttl' => 3600]; // Default YAML encoding (expanded format) $yaml = $serializer->serialize($config, 'yaml'); // Output: // environment: production // database: // host: localhost // port: 5432 // name: myapp // credentials: // user: admin // password: secret // cache: // driver: redis // ttl: 3600 // Inline format (more compact) $yaml = $serializer->serialize($config, 'yaml', [ YamlEncoder::YAML_INLINE => 2 // Inline at depth 2 ]); // Decode YAML $yamlData = "name: MyApp\nversion: 1.0\nfeatures:\n - auth\n - api"; $decoded = $serializer->decode($yamlData, 'yaml'); // $decoded = ['name' => 'MyApp', 'version' => '1.0', 'features' => ['auth', 'api']] ``` ## DiscriminatorMap Attribute The `#[DiscriminatorMap]` attribute enables polymorphic deserialization, allowing the serializer to instantiate the correct subclass based on a type field in the data. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Attribute\DiscriminatorMap; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; #[DiscriminatorMap(typeProperty: 'type', mapping: [ 'car' => Car::class, 'motorcycle' => Motorcycle::class, 'truck' => Truck::class, ])] abstract class Vehicle { public string $brand; public string $model; } class Car extends Vehicle { public int $doors; public string $fuelType; } class Motorcycle extends Vehicle { public int $engineCC; public bool $hasSidecar; } class Truck extends Vehicle { public float $cargoCapacity; public int $axles; } $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); $serializer = new Serializer( [new ObjectNormalizer($classMetadataFactory)], [new JsonEncoder()] ); // Deserialize to specific subclass based on "type" field $carJson = '{"type":"car","brand":"Toyota","model":"Camry","doors":4,"fuelType":"hybrid"}'; $car = $serializer->deserialize($carJson, Vehicle::class, 'json'); // $car is instance of Car class $motorcycleJson = '{"type":"motorcycle","brand":"Harley-Davidson","model":"Sportster","engineCC":1200,"hasSidecar":false}'; $motorcycle = $serializer->deserialize($motorcycleJson, Vehicle::class, 'json'); // $motorcycle is instance of Motorcycle class // Serialize includes the type property $truck = new Truck(); $truck->brand = 'Volvo'; $truck->model = 'FH16'; $truck->cargoCapacity = 25.5; $truck->axles = 3; $json = $serializer->serialize($truck, 'json'); // Output: {"type":"truck","brand":"Volvo","model":"FH16","cargoCapacity":25.5,"axles":3} ``` ## Context Options The serializer supports numerous context options for fine-tuning serialization behavior including circular reference handling, null value skipping, and type enforcement control. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; class Team { public string $name; public array $members = []; public ?Team $parentTeam = null; } class Member { public string $name; public ?Team $team = null; } $serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]); // Handle circular references $team = new Team(); $team->name = 'Engineering'; $member = new Member(); $member->name = 'Alice'; $member->team = $team; $team->members = [$member]; $json = $serializer->serialize($team, 'json', [ AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object) { return $object->name; // Return name instead of full object } ]); // Prevents infinite loop by returning name for circular refs // Skip null values class Profile { public string $name; public ?string $bio = null; public ?string $website = null; } $profile = new Profile(); $profile->name = 'John'; $json = $serializer->serialize($profile, 'json', [ AbstractObjectNormalizer::SKIP_NULL_VALUES => true ]); // Output: {"name":"John"} - null values omitted // Ignored attributes $json = $serializer->serialize($profile, 'json', [ AbstractNormalizer::IGNORED_ATTRIBUTES => ['bio', 'website'] ]); // Output: {"name":"John"} - specified attributes excluded // Populate existing object during deserialization $existingProfile = new Profile(); $existingProfile->name = 'Existing'; $existingProfile->bio = 'Original bio'; $data = '{"name":"Updated","website":"https://example.com"}'; $updatedProfile = $serializer->deserialize($data, Profile::class, 'json', [ AbstractNormalizer::OBJECT_TO_POPULATE => $existingProfile ]); // $updatedProfile->name = "Updated" // $updatedProfile->bio = "Original bio" (preserved) // $updatedProfile->website = "https://example.com" ``` ## Callbacks The callbacks context option allows transforming attribute values during serialization or deserialization with custom functions. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; class Order { public int $id; public float $amount; public string $currency; public \DateTimeInterface $createdAt; public string $status; } $serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]); $order = new Order(); $order->id = 1001; $order->amount = 99.99; $order->currency = 'USD'; $order->createdAt = new \DateTime('2024-03-15 10:30:00'); $order->status = 'pending'; // Apply callbacks during serialization $json = $serializer->serialize($order, 'json', [ AbstractNormalizer::CALLBACKS => [ // Format amount with currency symbol 'amount' => function ($value, $object, $attribute, $format, $context) { return number_format($value, 2) . ' ' . $object->currency; }, // Uppercase status 'status' => function ($value) { return strtoupper($value); }, // Custom date format 'createdAt' => function ($value) { return $value->format('M j, Y g:i A'); }, ] ]); // Output: {"id":1001,"amount":"99.99 USD","currency":"USD","createdAt":"Mar 15, 2024 10:30 AM","status":"PENDING"} ``` ## Error Handling with Collected Denormalization Errors The serializer can collect multiple denormalization errors instead of failing on the first one, useful for validating incoming data. ```php <?php use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Exception\PartialDenormalizationException; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; class Registration { public string $username; public int $age; public string $email; public bool $acceptedTerms; } $serializer = new Serializer( [new ObjectNormalizer(null, null, null, new ReflectionExtractor())], [new JsonEncoder()] ); // Invalid data with multiple type errors $invalidData = '{"username":123,"age":"not-a-number","email":"test@example.com","acceptedTerms":"yes"}'; try { $registration = $serializer->deserialize($invalidData, Registration::class, 'json', [ DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true ]); } catch (PartialDenormalizationException $e) { $errors = $e->getErrors(); foreach ($errors as $error) { echo sprintf( "Error at '%s': %s\n", $error->getPath(), $error->getMessage() ); } // Output: // Error at 'username': The type of the "username" attribute for class "Registration" must be string... // Error at 'age': The type of the "age" attribute for class "Registration" must be int... // You can still access the partially denormalized object $partialObject = $e->getData(); } ``` The Symfony Serializer component is essential for building APIs, data import/export features, and any application requiring data format transformations. Its primary use cases include converting PHP objects to JSON for REST APIs, parsing XML from external services, generating CSV reports, and handling complex object graphs with nested relationships and circular references. Integration typically involves configuring the serializer with appropriate normalizers (ObjectNormalizer, DateTimeNormalizer, ArrayDenormalizer) and encoders (JsonEncoder, XmlEncoder, CsvEncoder) based on required formats. In Symfony applications, the serializer is available as a service with automatic configuration; standalone usage requires manual instantiation with desired components. The component's attribute-based configuration (#[Groups], #[SerializedName], #[MaxDepth], #[Ignore]) provides declarative control over serialization behavior, while context options offer runtime flexibility for different serialization scenarios.