The concept is similar to Moshi, a Java/Kotlin serialization library - the least effort without sacrificing customizability, support for different formats or ease of use.
This is what it can serialize and deserialize out-of-the-box:
/** * @template T1 */class Item
{
/** * @param BackedEnumStub[] $array * @param Collection<int, T1> * @param T1 $generic * @param NestedGeneric<int, T1> $nested */publicfunction__construct(
// Scalarspublicreadonlyint$int,
publicreadonlyfloat$float,
publicreadonlystring$string,
publicreadonlybool$bool,
// Nullable and optional valuespublicreadonly ?string$nullableString,
publicreadonlyint|null|MissingValue$optional,
// Custom property names
#[SerializedName('two')] publicreadonlystring$one,
// Backed enumspublicreadonlyBackedEnumStub$backedEnum,
// Generics and nested objectspublicreadonlymixed$generic,
publicreadonlyNestedGenerics$nestedGeneric,
// Arrays and Illuminate Collection of any type (with generics!)publicreadonlyarray$array,
publicreadonlyCollection$collection,
// DatespublicreadonlyDateTime$dateTime,
publicreadonlyCarbon$carbon,
) {}
}You can then convert it into a "primitive" (scalars and arrays of scalars) or JSON:
$primitiveAdapter = $serializer->adapter(
PrimitiveTypeAdapter::class, NamedType::wrap(Item::class, [Carbon::class])
);
// -> ['int' => 123, ...]$primitiveAdapter->serialize(newItem(...));
$jsonAdapter = $serializer->adapter(
JsonTypeAdapter::class, NamedType::wrap(Item::class, [PrimitiveType::int()])
);
// new Item(123, ...)$jsonAdapter->deserialize('{"int": 123, ...}');Basic documentation is available in docs/. For examples, you can look at the test suite: tests/Integration.
There are some alternatives to this, but they usually lack one of the following:
- stupid simple internal structure: no node tree, no value/JSON wrappers, no in-repo custom reflection implementation, no PHP parsing
- doesn't rely on inheritance of serializable classes, hence allows serializing third-party classes
- parses existing PHPDoc information instead of duplicating it through attributes
- supports generic types which are quite useful for wrapper types
- allows simple extension through mappers and complex stuff through type adapters
- produces developer-friendly error messages for invalid data
- correctly handles optional (missing keys) and
nullvalues as separate concerns - simple to extend with additional formats