Example
{
"order_id": "A-1001",
"total": 59.9,
"paid": true,
"customer": {
"id": 7,
"email": "ada@example.com",
"phone": null
},
"items": [
{
"sku": "MUG-01",
"qty": 2
},
{
"sku": "TEE-04",
"qty": 1
}
]
}
<?php
declare(strict_types=1);
// $order = Order::fromArray(json_decode($json, true, flags: JSON_THROW_ON_ERROR));
final class Order
{
public function __construct(
public readonly string $orderId,
public readonly float $total,
public readonly bool $paid,
public readonly Customer $customer,
/** @var list<Item> */
public readonly array $items,
) {
}
/** @param array<string, mixed> $data */
public static function fromArray(array $data): self
{
return new self(
orderId: $data['order_id'],
total: $data['total'],
paid: $data['paid'],
customer: Customer::fromArray($data['customer']),
items: array_map(fn ($item) => Item::fromArray($item), $data['items']),
);
}
}
final class Customer
{
public function __construct(
public readonly int $id,
public readonly string $email,
public readonly mixed $phone,
) {
}
/** @param array<string, mixed> $data */
public static function fromArray(array $data): self
{
return new self(
id: $data['id'],
email: $data['email'],
phone: $data['phone'] ?? null,
);
}
}
final class Item
{
public function __construct(
public readonly string $sku,
public readonly int $qty,
) {
}
/** @param array<string, mixed> $data */
public static function fromArray(array $data): self
{
return new self(
sku: $data['sku'],
qty: $data['qty'],
);
}
}
order_idbecame$orderId;fromArray()still reads$data['order_id'].phoneis null, so its type is unknown and it becomesmixed. Paste a sample with a value to get?string.itemsis an array of objects, so it gets anItemclass and anarray_map.
Using the classes
$order = Order::fromArray(json_decode($json, true, flags: JSON_THROW_ON_ERROR));
echo $order->customer->email;
foreach ($order->items as $item) {
echo "{$item->sku} × {$item->qty}\n";
}
// Laravel: build the DTO from a validated request or an HTTP response
$order = Order::fromArray($request->validated());
$order = Order::fromArray(Http::get($url)->throw()->json());
Writing the frontend for the same API? Generate TypeScript interfaces too. For a machine-checkable contract, create a JSON Schema.
Frequently asked questions
How do I convert JSON to a PHP class?
Paste a JSON sample into the tool above. It writes a final class for every object, with typed constructor-promoted properties, nullable types for values that can be null or missing, list<…> docblocks for arrays, and a static fromArray() that builds the object, including nested objects, from json_decode($json, true).
Which PHP version do I need?
Constructor property promotion and named arguments need PHP 8.0, readonly properties need PHP 8.1. Untick readonly for PHP 8.0. Everything else works on any supported PHP version.
Why fromArray() instead of json_decode into the class?
json_decode only produces arrays or stdClass objects; it can’t create your classes. fromArray() maps each key to the matching property and builds nested objects, so you get typed objects that your IDE and static analysers such as PHPStan and Psalm understand.
Why is a float property given an integer?
json_decode returns an int for numbers written without a decimal point, such as 60. PHP converts int to float for float properties even with strict_types=1, so this works without any cast.
What about very large integers?
Integers beyond 64 bits would be rounded to float by json_decode. The converter types them as string and adds the JSON_BIGINT_AS_STRING flag to the decode example so they stay exact.