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.