Multi-format serialization for PHP 8.4+ — JSON, XML, CSV, QueryString, zero dependencies.
Installation · Quick Start · Attribute-Driven · All Encoders · Architecture
Multi-format serialization for PHP always pulls in heavy dependencies or loses the data contract:
// symfony/serializer: 7+ packages, complex config, annotation magic
// league/fractal: transformer boilerplate, no attribute support
// json_encode/decode alone: no groups, no field renaming, no XML/CSV
// Switching from JSON to XML means rewriting your serialization layer entirely.use KaririCode\Serializer\Provider\SerializerServiceProvider;
$engine = (new SerializerServiceProvider())->createEngine();
// One API, four formats — swap format string to change output
$json = $engine->serialize(['name' => 'Walmir', 'age' => 30], 'json');
$xml = $engine->serialize(['name' => 'Walmir', 'age' => 30], 'xml', ['root' => 'user']);
$csv = $engine->serialize([['name' => 'Walmir', 'age' => 30]], 'csv');
$qs = $engine->serialize(['name' => 'Walmir', 'age' => 30], 'query_string');
// RFC 8259 (JSON) · RFC 4180 (CSV) · RFC 3986 (URL) — built-in compliance| Requirement | Version |
|---|---|
| PHP | 8.4 or higher |
| ext-simplexml | Built-in (required for XML) |
| kariricode/property-inspector | ^2.0 |
composer require kariricode/serializer<?php
require_once __DIR__ . '/vendor/autoload.php';
use KaririCode\Serializer\Provider\SerializerServiceProvider;
$engine = (new SerializerServiceProvider())->createEngine();
// Serialize array to JSON
$result = $engine->serialize(['name' => 'Walmir', 'age' => 30], 'json');
echo $result->getPayload(); // '{"name":"Walmir","age":30}'
// Deserialize JSON to array
$data = $engine->deserialize('{"name":"Walmir"}', 'json');
// ['name' => 'Walmir']
// XML with custom root tag
$result = $engine->serialize(['name' => 'Walmir'], 'xml', ['root' => 'user']);
// <user><name>Walmir</name></user>use KaririCode\Serializer\Attribute\Serialize;
class UserDto
{
#[Serialize(name: 'user_id', groups: ['admin'])]
public int $id = 42;
#[Serialize(groups: ['public', 'admin'])]
public string $name = 'Walmir Silva';
#[Serialize(ignore: true)]
public string $passwordHash = '...';
}
$provider = new SerializerServiceProvider();
$serializer = $provider->createAttributeSerializer();
// Serialize to JSON (public group)
$json = $serializer->serialize(new UserDto(), 'json', ['public']);
// {"name":"Walmir Silva"}
// Serialize to JSON (admin group)
$json = $serializer->serialize(new UserDto(), 'json', ['admin']);
// {"user_id":42,"name":"Walmir Silva"}
// Deserialize from JSON
$dto = $serializer->deserialize('{"name":"Walmir"}', UserDto::class, 'json');| Format | Encoder | MIME Type | PHP Functions |
|---|---|---|---|
json |
JsonEncoder | application/json | json_encode/decode with JSON_THROW_ON_ERROR |
xml |
XmlEncoder | application/xml | SimpleXMLElement + DOMDocument |
csv |
CsvEncoder | text/csv | fputcsv/str_getcsv via php://temp |
query_string |
QueryStringEncoder | application/x-www-form-urlencoded | http_build_query/parse_str |
use KaririCode\Serializer\Contract\Encoder;
final readonly class YamlEncoder implements Encoder
{
public function encode(array $data, SerializationContext $context): string { /* ... */ }
public function decode(string $payload, SerializationContext $context): array { /* ... */ }
public function supports(string $format): bool { return $format === 'yaml'; }
public function getFormat(): string { return 'yaml'; }
}
$registry = $provider->createRegistry();
$registry->register(new YamlEncoder());$engine = (new SerializerServiceProvider())->createEngine();
$result = $engine->serialize(['name' => 'Walmir', 'age' => 30], 'json');
$result->getPayload(); // '{"name":"Walmir","age":30}'
$result->getFormat(); // 'json'
$result->getPayloadSize(); // byte count
$data = $engine->deserialize('{"name":"Walmir"}', 'json');
// ['name' => 'Walmir']
// CSV with custom separator
$result = $engine->serialize([['a' => 1, 'b' => 2]], 'csv', ['separator' => ';']);DPO Pipeline: Input → Validator → Sanitizer → Transformer → Business Logic
Infra Pipeline: Object ↔ Normalizer ↔ Array ↔ ★ Serializer ★ ↔ String
Cross-Layer: Request DTO ↔ Mapper ↔ Domain Entity ↔ Mapper ↔ Response DTO
The Serializer converts already-normalized arrays into wire-format strings for transport. It is the last step in the infrastructure pipeline before the payload leaves the application.
src/
├── Attribute/ Serialize — name, groups, ignore annotation
├── Configuration/ SerializerConfiguration (immutable)
├── Contract/ Encoder · SerializationContext · SerializerEngine · EncoderRegistry
├── Core/ SerializerEngine · SerializationContextImpl · InMemoryEncoderRegistry
├── Encoder/ JsonEncoder · XmlEncoder · CsvEncoder · QueryStringEncoder
├── Exception/ SerializationException
└── Provider/ SerializerServiceProvider — factory for engine & attribute serializer
| Decision | Rationale | ADR |
|---|---|---|
| Format-agnostic engine | Swap format string — no code changes | ADR-001 |
| Serialization groups | Field visibility per consumer without multiple DTOs | ADR-002 |
| RFC compliance | JSON 8259, CSV 4180, URL 3986 | ADR-003 |
| Property Inspector integration | Attribute scanning delegated to kariricode/property-inspector | ADR-004 |
| Zero encoder dependencies | All 4 encoders use only PHP built-ins | ADR-005 |
| Spec | Covers |
|---|---|
| SPEC-001 | Encoder interface and registration |
| SPEC-002 | #[Serialize] groups and field mapping |
| SPEC-003 | SerializeAttributeHandler contract and invariants |
| Metric | Value |
|---|---|
| PHP source files | 20 |
| Source lines | ~810 |
| Test files | 13 |
| Test lines | ~700 |
| External runtime dependencies | 1 (kariricode/property-inspector) |
| Encoder classes | 4 |
| Supported formats | JSON, XML, CSV, QueryString |
| PHPStan level | 9 |
| PHP version | 8.4+ |
| ARFA compliance | 1.3 |
git clone https://github.com/KaririCode-Framework/kariricode-serializer.git
cd kariricode-serializer
composer install
kcode init
kcode quality # Must pass before opening a PRPart of the KaririCode Framework ecosystem.
kariricode.org · GitHub · Packagist · Issues