Projectsphp-dataData Objects

PHP Data

Package

Lightweight, framework-agnostic Data Transfer Object (DTO) library with first-class Laravel integration.

Data Objects

A Data object extends BradieTilley\Data\Data and declares its shape as a typed constructor.

use BradieTilley\Data\Data;

class ProductData extends Data
{
    public function __construct(
        public string $title,
        public int $reviews,
        public float $rating,
    ) {}
}

Every public promoted property becomes part of the object's serialized shape. The constructor signature is the single source of truth — there is no separate schema to keep in sync.

Computed properties

You can set additional public properties in the constructor body. They are serialized alongside the promoted ones. Note that a non-promoted constructor argument (here $ratings) is used only to compute state and is not itself a property, so it is not serialized.

class CustomPropertiesData extends Data
{
    public float $averageRating;

    public function __construct(
        public string $title,
        array $ratings,
    ) {
        $this->averageRating = collect($ratings)->avg();
    }
}

CustomPropertiesData::from(['title' => 'Widget', 'ratings' => [4, 5, 3]])->toArray();
// ['title' => 'Widget', 'averageRating' => 4.0]

For properties that should never be hydrated from input, use #[Computed].

Default values

Constructor defaults are honoured when a value is absent from the input:

class DefaultPropertiesData extends Data
{
    public function __construct(
        public string $title,
        public bool $active = true,
    ) {}
}

DefaultPropertiesData::from(['title' => 'Widget'])->toArray();
// ['title' => 'Widget', 'active' => true]

Readonly properties

readonly promoted properties are fully supported and behave exactly as native PHP readonly properties.

class ReadonlyPropertiesData extends Data
{
    public function __construct(
        public readonly string $title,
    ) {}
}

Typed features at a glance

Property typeBehaviour
Scalars (string, int, float, bool)Copied as-is
BackedEnumScalar input is hydrated to the enum; serialized back to its scalar value
Nested DataRecursively hydrated / serialized — see Nested & Collections
array / CollectionOptionally typed per-item with #[ArrayOf]
Carbon / CarbonImmutableParsed on input, formatted on output (see #[DateFormat])

Continue to Hydration for the ways to build an instance.