Browser processing Input is processed on your device. Privacy & storage

JSON to PHP

Turn a JSON sample into PHP DTOs with typed properties, nullable types and the docblocks your IDE needs.

JSON input
PHP output

Property names are kept exactly as they appear in the JSON

PHP has no equivalent of @JsonProperty built into the language, so there is no way to write a rename annotation and have it just work. That makes keeping the original key the only honest choice: a key like isActive stays $isActive rather than being "prettified" into something that no longer matches the payload.

Keys that are not legal PHP identifiers (first-name, user id) are converted instead, since the alternative is a parse error.

<?php

class Root
{
    public int $id;
    public bool $isActive;
    public string $name;
    /** @var string[] */
    public array $tags;
    public ?string $website = null;
}

Typed properties or constructor promotion

StyleLooks likeNeeds
Typed properties One public property per key, assigned after construction. PHP 7.4+
Constructor promotion Properties declared directly in __construct. PHP 8.0+

Promotion produces far less code and makes the object immutable in practice, which is usually what you want for a DTO. Typed properties are better when a hydrator or an ORM needs to write to the object after construction.

Type mapping

JSON valuePHP type
whole numberint / ?int
decimal numberfloat / ?float
true / falsebool / ?bool
stringstring / ?string
arrayarray, with a @var T[] docblock
objectits own class
nullthe ? form, defaulted to null
mixed or unknownmixed

Why the array docblocks matter

PHP's array type says nothing about what is inside it, so public array $tags; gives your IDE nothing to work with — every foreach body ends up as a guessing game. The generator adds a /** @var string[] */ line above each array property, which is the convention PHPStan, Psalm and PhpStorm all understand.

Hydrating from a decoded payload

$data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

$root = new Root();
foreach ($data as $key => $value) {
    if (property_exists($root, $key)) {
        $root->$key = $value;
    }
}

This works precisely because the property names match the JSON keys. With a renamed property the loop would need a translation table, which is the maintenance burden this tool avoids.

Edge cases worth knowing

  • One class per file is the PSR-4 rule. The download puts every class in a single file, which PHP happily loads. If you follow PSR-4, split them into Root.php, Address.php and so on before committing.
  • ?mixed is not legal. mixed already includes null, so nullable unknown types stay as plain mixed.
  • Nested objects are not converted automatically. json_decode returns stdClass or arrays; constructing the child classes is your call.
  • Keys starting with a digit gain an underscore, since $2fa is not a valid variable name.

FAQ

Do I need PHP 7.4 or 8.0?

Typed properties need 7.4; constructor promotion needs 8.0. If you are still on 7.2 or 7.3, drop the type declarations — the property list itself is still correct.

Should I use json_decode with objects or arrays?

Arrays are easier to hydrate from and to validate. Objects are closer to the DTO shape you are building. Either works with this output; the example above uses arrays.

Why does an optional field get = null?

Without a default, an uninitialised typed property throws Error: must not be accessed before initialization. Defaulting to null makes the nullable type match the declared type and keeps the object safe to read.

Is my JSON uploaded?

No. The generator runs entirely in your browser.