Download the PHP package good-php/serialization without Composer
On this page you can find all versions of the php package good-php/serialization. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download good-php/serialization
More information about good-php/serialization
Files in good-php/serialization
Package serialization
Short Description Extendable reflection-based serializer with support for JSON and PHP primitive formats
License MIT
Informations about the package serialization
Good PHP serialization
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:
You can then convert it into a "primitive" (scalars and arrays of scalars) or JSON:
Custom mappers
Mappers are the simplest form customizing serialization of types. All you have
to do is to mark a method with either #[MapTo()]
or #[MapFrom]
attribute,
specify the type in question as first parameter or return type and the serializer
will handle the rest automatically. A single mapper may have as many map methods as you wish.
With mappers, you can even handle complex types - such as generics or inheritance:
Type adapter factories
Besides type mappers which satisfy most of the needs, you can use type adapter factories to precisely control how each type is serialized.
The idea is the following: when building a serializer, you add all of the factories you want to use in order of priority:
A factory has the following signature:
If you return null
, the next factory is called. Otherwise, the returned type adapter is used.
The serialized is entirely built using type adapter factories. Every type that is
supported out-of-the-box also has it's factory and can be overwritten just by doing
->addFactoryLast()
. Type mappers are also just fancy adapter factories under the hood.
This is how you can use them:
In this example, NullableTypeAdapterFactory
handles all nullable types. When a non-nullable
type is given, it returns null
. That means that the next in "queue" type adapter will be
called. When a nullable is given, it returns a new type adapter instance which has two
methods: serialize
and deserialize
. They do exactly what they're called.
Naming of keys
By default serializer preserves the naming of keys, but this is easily customizable (in order of priority):
- specify a custom property name using the
#[SerializedName]
attribute - specify a custom naming strategy per class using the
#[SerializedName]
attribute - specify a custom global naming strategy (use one of the built in or write your own)
Here's an example:
Out of the box, strategies for snake_case
, camelCase
and PascalCase
are provided,
but you it's trivial to implement your own:
Required, nullable, optional and default values
By default if a property is missing in serialized payload:
- nullable properties are just set to null
- properties with a default value - use the default value
- optional properties are set to
MissingValue::INSTANCE
- any other throw an exception
Here's an example:
Flattening
Sometimes the same set of keys/types is shared between multiple other models. You could use inheritance for this, but we believe in composition over inheritance and hence provide a simple way to achieve the same behaviour without using inheritance:
Here's an example:
Error handling
This is expected to be used with client-provided data, so good error descriptions is a must. These are some of the errors you'll get:
- Expected value of type 'int', but got 'string'
- Expected value of type 'string', but got 'NULL'
- Failed to parse time string (2020 dasd) at position 5 (d): The timezone could not be found in the database
- Expected value of type 'string|int', but got 'boolean'
- Expected one of [one, two], but got 'five'
- Could not map item at key '1': Expected value of type 'string', but got 'NULL'
- Could not map item at key '0': Expected value of type 'string', but got 'NULL' (and 1 more errors)."
- Could not map property at path 'nested.field': Expected value of type 'string', but got 'integer'
All of these are just a chain of PHP exceptions with previous
exceptions. Besides
those messages, you have all of the thrown exceptions with necessary information.
More formats
You can add support for more formats as you wish with your own type adapters. All of the existing adapters are at your disposal:
Why this over everything else?
There are some alternatives to this, but all of them will lack at least one of these:
- doesn't rely on inheritance, hence allows serializing third-party classes
- parses existing PHPDoc information instead of duplicating it through attributes
- supports generic types which are extremely 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
null
values as separate concepts - simple to extend with additional formats
- simple internal structure: no node tree, no value wrappers, no PHP parsing, no inherent limitations
All versions of serialization with dependencies
php-ds/php-ds Version ^1.3.0
good-php/reflection Version ^1.0
tenantcloud/php-standard Version ^2.0