JSON to PHP
Generate PHP 8 classes with typed, constructor-promoted properties and a fromArray() hydrator from any JSON object.
PHP 8.0+ — uses constructor property promotion. No dependencies.
Paste a JSON object and get back PHP 8 classes with typed, constructor-promoted properties and a fromArray() hydrator — nested objects become their own classes, arrays of objects hydrate with array_map(), and every property is typed instead of living in an untyped associative array.
- ✓PHP 8 constructor property promotion — no boilerplate property declarations
- ✓Nested objects become their own typed classes automatically
- ✓Arrays of objects hydrate with array_map(), fully typed
- ✓@var docblocks on array properties so PHPStan/Psalm understand element types
- ✓100% private — the class is generated entirely in your browser
Why typed PHP classes instead of an array?
Decoding JSON in PHP with json_decode($json, true) gives you a plain associative array — fast, but with no autocomplete, no static analysis, and a typo in a key name only surfaces at runtime. Hydrating into a typed class instead means your IDE, PHPStan, and Psalm can all catch mistakes before the code ever runs, and the shape of your data is documented in one place instead of scattered across every call site that reads $data['user']['email'].
stdClass vs. Associative Array vs. Generated Class
| json_decode($j, true) | json_decode($j) | Generated class | |
|---|---|---|---|
| Access syntax | $data['name'] | $data->name | $data->name |
| Typed properties | No | No | Yes |
| IDE autocomplete | No | Partial (dynamic) | Full |
| Static analysis catches typos | No | No | Yes — PHPStan/Psalm |
| Nested data typing | None — nested arrays | None — nested stdClass | Nested classes, fully typed |
Using the Generated Class
<?php
$json = file_get_contents('user.json');
$data = json_decode($json, true);
$user = User::fromArray($data);
echo $user->name; // Ravi Kumar
echo $user->address->city; // Surat
// Re-encode back to JSON
echo json_encode($user);Constructor property promotion (PHP 8.0+) means the class body is just the typed parameter list — no separate property declarations, no boilerplate assignment statements. Nested objects become their own classes with their own fromArray(), and arrays of objects are hydrated with array_map() so a list of orders becomes a list of typed Order instances, not an array of raw associative arrays.
A Note on Types
Every field's type is inferred from the sample value you paste in — a field that is null in your sample becomes mixed(since a single example can't tell the difference between "always null" and "sometimes null, sometimes a string"), and array element types are inferred from the array's first non-null item. Review the generated types against your actual API contract before shipping — the generator gets you most of the way there, not all the way.
Making It Immutable: readonly Properties (PHP 8.1+)
A hydrated API response object generally shouldn't be mutated after construction — add PHP 8.1's readonly modifier to enforce that at the language level instead of just by convention:
final class User
{
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly int $age,
) {}
public static function fromArray(array $data): self
{
return new self(
name: $data['name'],
email: $data['email'],
age: $data['age'],
);
}
}
$user = User::fromArray($data);
$user->name = "Changed"; // Error: Cannot modify readonly property User::$nameThe generator emits plain (mutable) properties by default for the broadest PHP 8.0+ compatibility — add readonlyyourself once you know you're targeting 8.1 or later and want the extra safety.
Common Use Cases
- ▸Typed DTOs for an API response — Hydrate a third-party or internal API's JSON directly into a typed object instead of passing an untyped array through your codebase
- ▸Laravel API Resources — Use a generated class as the typed input to a JsonResource's toArray(), instead of reading raw array keys with no autocomplete
- ▸Symfony Serializer targets — Point Symfony's Serializer denormalizer at the generated class to get typed objects straight out of deserialization
- ▸Webhook payload handling — Hydrate an incoming webhook's JSON body into a typed class so your handler code gets IDE autocomplete and static analysis instead of guessing array keys