Projectsphp-dataHydration

PHP Data

Package

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

Hydration

Hydration turns some input into a typed Data instance. Every property is resolved from the input, cast to the declared type where the library knows how, and passed to the constructor.

from() — the universal entrypoint

Data::from() accepts many input shapes and dispatches to the right strategy:

ProductData::from(['title' => 'Widget', 'reviews' => 5, 'rating' => 4.5]); // array
ProductData::from($eloquentModel);   // Eloquent model (Laravel)
ProductData::from($otherDataObject); // another Data instance
ProductData::from($stdClass);        // stdClass
ProductData::from('{"title":"…"}');  // JSON string
ProductData::from($anyObject);       // arbitrary object (by public property)

Array input: named or positional

Array keys are matched to constructor parameter names first, then fall back to positional index:

// named
ProductData::from(['title' => 'Widget', 'reviews' => 5, 'rating' => 4.5]);

// positional
ProductData::from(['Widget', 5, 4.5]);

make() — explicit named arguments

make() is a thin wrapper that constructs from named arguments while still running the same casting pipeline (so nested arrays become nested Data, enums are hydrated, etc.):

ProductData::make(
    title: 'Widget',
    reviews: 5,
    rating: 4.5,
);

make() gives you full IDE autocomplete and static analysis on the argument list.

Other constructors

MethodInput
from(mixed $data)Anything below — auto-detected
fromArray(array $data)An associative or positional array
fromData(Data $data)Another Data instance (re-cast to this type)
fromModel(mixed $model)An Eloquent model (Laravel)
fromClass(object $object)Any object, read by public properties
make(mixed ...$args)Named/positional arguments

For Eloquent-specific patterns (WhenLoaded, WhenCounted, …), see Laravel Integration.

Casting during hydration

from()/make() apply these conversions automatically based on the property type:

  • #[WithCast] / #[WithCastAndTransformer] → a local cast runs first and takes precedence over the built-ins below. See Casts & Transformers.
  • Nested Data → recursively hydrated.
  • BackedEnum → a scalar ('active') becomes the matching case; an enum instance passes through unchanged.
  • array / Collection with #[ArrayOf(Child::class)] → each element is hydrated to Child. See Nested & Collections.
  • Carbon / CarbonImmutable → parsed via Carbon::parse() (when Carbon is installed).
  • Lazy values → deferred until serialization (see Optional, Lazy & Computed).
  • Laravel #[WhenLoaded] / #[WhenCounted] / #[WhenAppended] / #[When] → when the input is an Eloquent model, gate the property (and optional using transform) before casting. See Laravel Integration.

Custom casts never receive null — a null on a nullable/optional property stays null (use a magic method or default if you need to invent a value).

Missing and null values

  • A missing value falls back to the constructor default when one exists.
  • A null value for a nullable property stays null.
  • A missing value for a property typed Sometimes|T is treated as absent and omitted from toArray() — see Sometimes.
  • A null value for a non-nullable, non-optional property throws a RuntimeException.