squidit / array-to-object
Hydrate array to object using typed object properties
Requires
- php: ^8.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.57
- phpbench/phpbench: ^1.2
- phpstan/phpstan: ^1.11
- phpunit/phpunit: ^11.1
- squidit/php-coding-standards: ^1.1
README
Create an object from array data by mapping provided array keys to corresponding typed class property names.
The array keys must match the names of the object properties.
Usage - example:
<?php declare(strict_types=1); use SquidIT\Hydrator\ArrayToObject; use SquidIT\Hydrator\Class\ClassInfoGenerator; use SquidIT\Hydrator\Tests\Unit\ExampleObjects\Car\Complete\CarComplete; $classInfoGenerator = new ClassInfoGenerator(); $hydrator = new ArrayToObject($classInfoGenerator); $data = [ 'color' => 'black', 'nrOfDoors' => 4, 'mileagePerLiter' => 16.3, 'passengerList' => ['melvin', 'bert'], 'manufacturer' => [ 'addressLine1' => 'Beautiful Street 123', 'addressLine2' => 'Apartment 1234', 'city' => 'Rotterdam', 'employeeList' => [ ['employeeName' => 'cecil'], ['employeeName' => 'melvin'], ], ], 'interCoolers' => [ [ 'speedRangeMinRpm' => 200, 'speedRangeMaxRpm' => 2160, 'isWaterCooled' => true, 'speedCategory' => 'fast', ], [ 'speedRangeMinRpm' => 100, 'speedRangeMaxRpm' => 2200, 'isWaterCooled' => false, 'speedCategory' => 'slow', ], ], 'countryEntryDate' => '2015-06-01 13:45:01', 'extraInfo' => null, ]; $carComplete = $hydrator->hydrate($data, CarComplete::class); var_dump($carComplete);
output
object(SquidIT\Hydrator\Tests\Unit\ExampleObjects\Car\Complete\CarComplete)#6 (9) {
["color"]=>
string(5) "black"
["nrOfDoors"]=>
int(4)
["mileagePerLiter"]=>
float(16.3)
["passengerList"]=>
array(2) {
[0]=>
string(6) "melvin"
[1]=>
string(4) "bert"
}
["manufacturer"]=>
object(SquidIT\Hydrator\Tests\Unit\ExampleObjects\Manufacturer\Honda)#21 (4) {
["addressLine1"]=>
string(20) "Beautiful Street 123"
["addressLine2"]=>
string(14) "Apartment 1234"
["city"]=>
string(9) "Rotterdam"
["employeeList"]=>
array(2) {
[0]=>
object(SquidIT\Hydrator\Tests\Unit\ExampleObjects\Manufacturer\Employee)#24 (1) {
["employeeName"]=>
string(5) "cecil"
}
[1]=>
object(SquidIT\Hydrator\Tests\Unit\ExampleObjects\Manufacturer\Employee)#10 (1) {
["employeeName"]=>
string(6) "melvin"
}
}
}
["interCoolers"]=>
array(2) {
[0]=>
object(SquidIT\Hydrator\Tests\Unit\ExampleObjects\Car\Parts\InterCooler)#14 (4) {
["speedRangeMinRpm"]=>
int(200)
["speedRangeMaxRpm"]=>
int(2160)
["isWaterCooled"]=>
bool(true)
["speedCategory"]=>
enum(SquidIT\Hydrator\Tests\Unit\ExampleObjects\Car\Speed::FAST)
}
[1]=>
object(SquidIT\Hydrator\Tests\Unit\ExampleObjects\Car\Parts\InterCooler)#44 (4) {
["speedRangeMinRpm"]=>
int(100)
["speedRangeMaxRpm"]=>
int(2200)
["isWaterCooled"]=>
bool(false)
["speedCategory"]=>
enum(SquidIT\Hydrator\Tests\Unit\ExampleObjects\Car\Speed::SLOW)
}
}
["countryEntryDate"]=>
object(DateTimeImmutable)#39 (3) {
["date"]=>
string(26) "2015-06-01 13:45:01.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}
["extraInfo"]=>
NULL
["isInsured"]=>
bool(true) <--- object default property and was not present in our data array
}
Nested objects
If a class property contains a nested object, the hydrator can infer the object type by reading the property type.
In the example below, the Car::class
contains a named property manufacturer
which is of type Honda::class
.
When hydrating, we need to provide all data required to create a Honda object.
class Car { public function __construct( public string $color, public Honda $manufacturer, ) {} } $data = [ 'color' => 'black', 'manufacturer' => [ // <-- Honda::class 'name' => 'Beautiful Street 124', 'city' => 'Rotterdam', 'employeeList' => [] ], ];
Nested objects: Array of objects
If a class property contains an array of objects, we need to add a property attribute:
SquidIT\Hydrator\Attributes\ArrayOf([CLASSNAME])
.
In the example below, the Honda::class
contains a property employeeList
which should contain an array of
Employee::class
objects.
By adding the property attribute SquidIT\Hydrator\Attributes\ArrayOf(Employee::class)
our hydrator knows how to hydrate
array data found under the 'employeeList' array key.
use SquidIT\Hydrator\Attributes\ArrayOf; class Honda implements ManufacturerInterface { /** * @param array<int, Employee> $employeeList */ public function __construct( public string $name, public string $city, #[ArrayOf(Employee::class)] public array $employeeList, ) {} }
Type casting/juggling array vales into object properties
It is important to note that the hydrator will only work on classes that only contain typed properties.
If a non typed property is found an SquidIT\Hydrator\Exceptions\AmbiguousTypeException
exception will be thrown.
The hydrator supports casting into the following property types
int:
if a string contains only digits (plus and minus signs are allowed)
bool:
The following values will be cast to true
1
[int]'true'
[string]'1'
[string]'y'
[string]'yes'
[string]
The following values will be cast to false
0
[int]'false'
[string]'0'
[string]'n'
[string]'no'
[string]
DateTimeImmutable::class:
Any string value supported by strtotime()
please note: as author of this library I feel no need to support the DateTime::class
BackedEnum:
Any integer of string backed enum value
UnionTypes:
❌ Union types are not supported because we are unable to infer concrete object type implementation.