What is JSON to PHP Class Generator?
PHP's built-in json_decode returns one of two very different things depending on its second argument: call json_decode($s) and you get a stdClass object with -> property access; call json_decode($s, true) and you get an associative array with [] access. Neither gives you type safety, IDE autocompletion, or a place to attach behavior. Converting JSON into a proper PHP class with typed properties solves all three, and that is what this generator does — it infers a PHP type for each field, builds a class with constructor and fromJson/toJson methods, and orders nested classes children-first so they are defined before use. The big shift in modern PHP is typed properties, added in PHP 7.4 and made far more ergonomic by constructor property promotion in PHP 8.0. Promotion lets you declare and assign a property in a single constructor parameter: public function __construct(public int $id, public ?string $name). The type declarations are enforced at runtime — assigning a string to an int property throws a TypeError — which turns a loosely typed array into a self-validating value object. The generator also offers a Laravel Eloquent mode. Eloquent models are not plain value objects; they extend the framework base class and lean on $fillable for mass-assignment protection and $casts to coerce database columns into the right PHP types. That is a different shape from a DTO, so the tool emits it separately.
How to Use
- Set the class name and a namespace matching your PSR-4 autoload root (e.g. App\\DTO) so the file is discoverable by Composer
- Choose PHP 8 constructor promotion for compact typed DTOs, or Laravel Eloquent mode if the data maps to a database model
- Paste your JSON and click Generate — nullable JSON fields become ?type and arrays become typed array properties
- Copy the output into a file named after the class (PSR-4 requires one class per file, filename matching class name)
- For Eloquent mode, move the generated class into app/Models and confirm $casts matches your migration column types
Why Use This Tool?
Tips & Best Practices
- json_decode($s) returns stdClass (-> access) while json_decode($s, true) returns an associative array ([] access). Pick one convention project-wide; the generated fromJson assumes the associative-array form because it is easier to iterate and validate.
- Constructor promotion needs PHP 8.0+. On 7.4 you still get typed properties but must write the assignments by hand — the generator falls back automatically when you do not select promotion.
- A typed property with no default and no nullable marker is in an uninitialized state until assigned; reading it throws an Error, not null. Make optional fields ?type so a missing JSON key yields null instead of a fatal error.
- In Laravel, $casts controls how Eloquent converts a database column to a PHP type when you read $model->field. JSON booleans stored as tinyint columns need "field" => "boolean" in $casts or you will get 1/0 instead of true/false.
- Eloquent\u2019s $fillable is a security control, not a serialization hint: any column not listed there is silently ignored by Model::create() and ::fill(). If a field is not saving, check $fillable before anything else.
Frequently Asked Questions
What is the complete JSON type to PHP type mapping?
JSON string → string; JSON integer → int; JSON float → float; JSON boolean → bool; JSON null → a nullable type such as ?string or ?int; JSON array of one type → array (PHP has no generic array type, so the element type lives in a docblock like /** @var Item[] */); JSON object → a separate typed class. PHP 8 union types let a sometimes-null field be written as ?Type, which is shorthand for Type|null.
What is the difference between json_decode returning stdClass vs an array?
json_decode($json) with no second argument returns a stdClass object, where you read fields with arrow syntax: $data->userId. Passing true as the second argument, json_decode($json, true), returns a nested associative array read with bracket syntax: $data["userId"]. stdClass is convenient for quick reads but offers no type guarantees and no methods; the associative array is easier to loop over and validate. Generated fromJson methods use the array form so they can iterate keys and construct nested classes uniformly.
What are typed properties and which PHP version do I need?
Typed properties (PHP 7.4+) let you declare a type directly on a class property: public int $id;. Assigning a wrong type throws a TypeError at runtime. PHP 8.0 added constructor property promotion, which collapses declaration and assignment into the constructor signature. Note that a typed property without a default starts uninitialized — reading it before assignment throws an Error rather than returning null — so optional fields should be declared as ?type to default to null.
How does this relate to Laravel Eloquent models?
A plain DTO class is just a typed container. An Eloquent model extends Illuminate\\Database\\Eloquent\\Model and is tied to a database table. Eloquent mode emits $fillable (the whitelist of columns mass-assignable via create()/fill(), a protection against over-posting) and $casts (which coerces raw column values into PHP types like bool, float, datetime, or array when you read them). Use the DTO form for API payloads you do not persist, and the Eloquent form when the JSON maps onto a table you query and save.
How are nested objects handled?
Each nested JSON object becomes its own PHP class, emitted before the parent (children-first) so it is defined when referenced. The parent class type-hints the nested class in its constructor and delegates to the child fromJson/toJson inside its own methods. For PSR-4 autoloading you must then split these into one file per class, each filename matching its class name, under the namespace directory.
Is my data sent to a server?
No, all processing happens entirely in your browser. Your JSON data never leaves your device.
Real-world Examples
A typed DTO with constructor promotion and a nullable field (PHP 8)
An API returns a user where the avatar URL may be null. With PHP 8 promotion selected, the class declares and assigns every property in the constructor signature, and the nullable field becomes ?string so a missing avatar yields null rather than an uninitialized-property error.
{
"id": 1024,
"username": "marie",
"verified": true,
"avatarUrl": null,
"score": 87.5
}<?php
namespace App\DTO;
final class User
{
public function __construct(
public int $id,
public string $username,
public bool $verified,
public ?string $avatarUrl,
public float $score,
) {}
public static function fromJson(array $data): self
{
return new self(
id: $data['id'],
username: $data['username'],
verified: $data['verified'],
avatarUrl: $data['avatarUrl'] ?? null,
score: $data['score'],
);
}
public function toJson(): array
{
return [
'id' => $this->id,
'username' => $this->username,
'verified' => $this->verified,
'avatarUrl' => $this->avatarUrl,
'score' => $this->score,
];
}
}A Laravel Eloquent model with $fillable and $casts
The same shape mapped onto a database table. Eloquent mode extends Model, lists every column in $fillable so create() accepts them, and declares $casts so the boolean column and float column come back as real bool/float values instead of raw strings from the driver.
{
"title": "Hello World",
"published": true,
"viewCount": 0,
"rating": 4.2
}<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'title',
'published',
'view_count',
'rating',
];
protected $casts = [
'published' => 'boolean',
'view_count' => 'integer',
'rating' => 'float',
];
}
// $post = Post::create($request->validated());