Serde: A modern serialization library for PHP 8.1

in PHP2 months ago (edited)

A while back, I announced the release of my AttributeUtils library and its powerful attribute-based analyzer.

That library was built primarily to support the many edge cases I needed for Crell/Serde, a new, robust serialization/deserialization library built specifically for PHP 8.1.

The basics

Serde is designed to be usable out-of-the-box with no further configuration, but also to support highly flexible configuration. For most common use cases, this is sufficient:

use Crell\Serde\SerdeCommon;

$serde = new SerdeCommon();

$object = new SomeClass();
// Populate $object somehow;

$jsonString = $serde->serialize($object, format: 'json');

$deserializedObject = $serde->deserialize($jsonString, from: 'json', to: SomeClass::class);

(The named arguments are optional, but recommended.)

Serde supports JSON, YAML, and PHP array formats, plus streaming JSON output to a file handle. XML support is in progress.

Most basic value objects can be handled without any further configuration. They "just work." It even fully supports readonly properties and enums!

Customizing Serde

Most of Serde's behavior is configurable via attributes. Properties of objects are serialized by default, but you can opt them out, or switch to opt-in. For example:

use Crell\Serde\Attributes as Serde;

#[Serde\ClassSettings(includeFieldsByDefault: false)]
class Person
{
    #[Serde\Field(serializedName: 'callme')]
    protected string $name = 'Larry';
}

Thanks to the robust support from AttributeUtils, Serde is able to extensively manipulate the data both inbound and outbound. That makes it ideal for translating data from legacy formats to a clean object structure. For instance, it supports "flattening" and "collecting", that is, translating an object or array property into a flat list of values and back again. It can even do so with multiple object properties in the same class. For an example from the documentation:

use Crell\Serde\Attributes as Serde;

class Results
{
    public function __construct(
        #[Serde\Field(flatten: true)]
        public Pagination $pagination,
        #[Serde\SequenceField(arrayType: Product::class)]
        public array $products,
    ) {}
}

class Pagination
{
    public function __construct(
        public int $total,
        public int $offset,
        public int $limit,
    ) {}
}

class Product
{
    public function __construct(
        public string $name,
        public float $price,
    ) {}
}

When serialized, the $pagination object will get "flattened," meaning its three properties will be included directly in the properties of Results. Therefore, a JSON-serialized copy of this object may look like:

{
    "total": 100,
    "offset": 20,
    "limit": 10,
    "products": [
        {
            "name": "Widget",
            "price": 9.99
        },
        {
            "name": "Gadget",
            "price": 4.99
        }
    ]
}

Serde also supports both static and dynamic type maps, which allow you to import and export to different objects in the same inheritance hierarchy. That translation can be specified directly on the class, or via a service that can do arbitrary lookups, such as in user configuration or the database. And it's all thoroughly documented.

Thanks to the "Scopes" support in AttributeUtils, Serde fully supports an equivalent to serialization groups, allowing an object to be serialized or deserialized in different ways in different contexts.

Both custom object types and custom formats are fully supported, although in practice I expect most people won't need them.

More information about all of these features and many more are available in the README file.

Use it today

Serde is currently a 0.5.0 release, and I consider it a release candidate. I'm comfortable tagging it as a stable 1.0.0, but I want to see if it can get a bit more use first just in case there's any bugs found that might force an API change. I don't expect there to be any.

Future planned development, if time permits, includes finishing XML support, improved streaming, and multi-record support. I may also consider formats like CSV, TOML, or NEON to be fair targets for future extension.

Give it a whirl and drop a note on GitHub if you find it useful, find an issue, or both. :-)

Thanks to TYPO3 GmbH for sponsoring development of both libraries.

Sort:  

Thanks for your contribution to the STEMsocial community. Feel free to join us on discord to get to know the rest of us!

Please consider delegating to the @stemsocial account (85% of the curation rewards are returned).

You may also include @stemsocial as a beneficiary of the rewards of this post to get a stronger support.