What Does Mapping Input into a Strongly-Typed Value Object Structure Mean in Valinor?

Updated

Valinor is a PHP library that maps arbitrary input—arrays, JSON-decoded data, or other sources—into strongly-typed PHP value objects. "Mapping" means taking raw, loosely-typed data and producing a fully constructed object whose properties have declared types (e.g., int, string, DateTimeImmutable, nested objects). "Strongly-typed" means those declared types are enforced during construction, so type errors surface at the mapping boundary rather than later in your application logic.

The core idea

In plain PHP, input usually arrives as an array or stdClass:

$data = json_decode($request->getBody(), true);
// ['id' => '42', 'name' => 'Ada', 'created_at' => '2024-01-15']

Every value is a string or a nested array. Nothing stops you from passing '42' where an int is expected, or forgetting a key entirely.

Valinor lets you declare a target class and maps the input into an instance of it:

final class User
{
    public function __construct(
        public readonly int $id,
        public readonly string $name,
        public readonly DateTimeImmutable $createdAt,
    ) {}
}

The mapper reads the input, matches keys to constructor parameters, converts compatible values (like the string '42' to int), and constructs the object. If a value cannot be converted or a required field is missing, mapping fails instead of silently producing a broken object.

What "strongly-typed" changes in practice

Concern Manual array handling Valinor mapping
Field types Untyped; checked only if you write checks Declared on the object; enforced at mapping
Missing keys null or undefined-index warnings Mapping error you can catch
Nested structures Manual recursion Nested objects mapped from nested input
Conversion Hand-written casts Built-in conversion where types allow
Failure point Anywhere the value is later used At the mapping boundary

The practical benefit: by the time your code receives the object, its shape and types are already guaranteed. Downstream code can rely on $user->id being an int without defensive checks.

Where the input comes from

The input is not limited to JSON. Anything that can be represented as arrays or scalar values—decoded request bodies, configuration arrays, database rows, or test fixtures—can be mapped, as long as it matches the structure your target class expects.

When this matters

Mapping to typed objects is most useful at boundaries: HTTP request handling, API response parsing, config loading, or any place where external data enters your application. It moves validation and conversion to one predictable location instead of scattering casts and isset() checks throughout your code.

For the exact API, supported types, and configuration options, refer to the library's current documentation, since the site redirects to a versioned path and details may change between releases.