JSON → PHP 8.2+ DTO
Arquitectura PHP moderna

Generador de DTOs Tipados Readonly en PHP 8.2+ desde JSON

Convierte datos JSON en modernos DTOs con clases readonly de PHP 8.2+, promoción de constructor y deserializadores fromArray.

Preajustes
Carga Útil JSON de OrigenVálido
<?php

declare(strict_types=1);

namespace App\DTO;

/**
 * @param string[] $tags
 */
final readonly class UserDto implements \JsonSerializable
{
    public function __construct(
        public string $id,
        public string $email,
        public string $username,
        public string $displayName,
        public string $role,
        public bool $isActive,
        public TenantDto $tenant,
        public PreferencesDto $preferences,
        /** @var string[] */
        public array $tags = [],
        public \DateTimeImmutable $lastLoginAt,
        public \DateTimeImmutable $createdAt,
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            id: (string) ($data['id'] ?? $data['id'] ?? null ?? ''),
            email: (string) ($data['email'] ?? $data['email'] ?? null ?? ''),
            username: (string) ($data['username'] ?? $data['username'] ?? null ?? ''),
            displayName: (string) ($data['display_name'] ?? $data['displayName'] ?? null ?? ''),
            role: (string) ($data['role'] ?? $data['role'] ?? null ?? ''),
            isActive: (bool) ($data['is_active'] ?? $data['isActive'] ?? null ?? false),
            tenant: TenantDto::fromArray((array) ($data['tenant'] ?? [])),
            preferences: PreferencesDto::fromArray((array) ($data['preferences'] ?? [])),
            tags: array_map(fn($item) => (string) $item, (array) ($data['tags'] ?? [])),
            lastLoginAt: isset($data['last_login_at']) ? new \DateTimeImmutable((string) $data['last_login_at']) : null,
            createdAt: isset($data['created_at']) ? new \DateTimeImmutable((string) $data['created_at']) : null,
        );
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'email' => $this->email,
            'username' => $this->username,
            'display_name' => $this->displayName,
            'role' => $this->role,
            'is_active' => $this->isActive,
            'tenant' => $this->tenant->toArray(),
            'preferences' => $this->preferences->toArray(),
            'tags' => $this->tags,
            'last_login_at' => $this->lastLoginAt?->format(\DateTimeInterface::ATOM),
            'created_at' => $this->createdAt?->format(\DateTimeInterface::ATOM),
        ];
    }

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
}

final readonly class TenantDto implements \JsonSerializable
{
    public function __construct(
        public string $id,
        public string $name,
        public string $tier,
        public int $activeSeats,
        public string $billingContact,
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            id: (string) ($data['id'] ?? $data['id'] ?? null ?? ''),
            name: (string) ($data['name'] ?? $data['name'] ?? null ?? ''),
            tier: (string) ($data['tier'] ?? $data['tier'] ?? null ?? ''),
            activeSeats: (int) ($data['active_seats'] ?? $data['activeSeats'] ?? null ?? 0),
            billingContact: (string) ($data['billing_contact'] ?? $data['billingContact'] ?? null ?? ''),
        );
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'tier' => $this->tier,
            'active_seats' => $this->activeSeats,
            'billing_contact' => $this->billingContact,
        ];
    }

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
}

final readonly class PreferencesDto implements \JsonSerializable
{
    public function __construct(
        public string $theme,
        public bool $notificationsEnabled,
        public string $locale,
        public string $timezone,
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            theme: (string) ($data['theme'] ?? $data['theme'] ?? null ?? ''),
            notificationsEnabled: (bool) ($data['notifications_enabled'] ?? $data['notificationsEnabled'] ?? null ?? false),
            locale: (string) ($data['locale'] ?? $data['locale'] ?? null ?? ''),
            timezone: (string) ($data['timezone'] ?? $data['timezone'] ?? null ?? ''),
        );
    }

    public function toArray(): array
    {
        return [
            'theme' => $this->theme,
            'notifications_enabled' => $this->notificationsEnabled,
            'locale' => $this->locale,
            'timezone' => $this->timezone,
        ];
    }

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
}
3 Classes
Clases DTO Generadas
20 Campos
Propiedades Tipadas
0 ms de retardo de servidor
Motor PHP 8.2+ Readonly

Clases Readonly de PHP 8.2+ y Promoción de Constructor

Aprovecha las modernas clases readonly de PHP 8.2 con promoción de propiedades en constructor e inmutabilidad profunda para máxima seguridad de tipos.

Garantía de Privacidad 100% en Cliente

Todo el análisis JSON, deducción de AST y generación de PHP se ejecutan estrictamente en la memoria de su navegador sin enviar datos a servidores externos.

Serialización y Deserialización Bidireccional

Genera métodos estáticos fromArray() con hidratación recursiva de DTOs anidados, además de implementaciones toArray() y JsonSerializable.

Referencia técnica y guía de arquitectura

Guía para Desarrolladores del Generador de DTOs Tipados Readonly en PHP 8.2+ desde JSON — Guía de referencia

Convierte datos JSON en modernos DTOs con clases readonly de PHP 8.2+, promoción de constructor y deserializadores fromArray.

Parámetros clave y controles

Root Class NameString (Identificador PHP)

Identificador de la clase de nivel superior generada para el objeto JSON raíz.

Por defecto: RootDto
NamespaceString (Namespace PHP)

Declaración de namespace compatible con PSR-4 antepuesta a los archivos DTO generados.

Por defecto: App\DTO
PHP Target VersionEnum ('8.2+', '8.1', '8.0')

Sintaxis de versión de destino; 8.2+ utiliza declaraciones de readonly class con promoción de constructor.

Por defecto: 8.2+
Constructor PromotionBoolean

Declara e inicializa propiedades tipadas directamente en la firma de argumentos de __construct().

Por defecto: true
Deserializer Hydration (fromArray)Boolean

Genera un método de fábrica estático y seguro de tipos fromArray(array $data): self con hidratación recursiva.

Por defecto: true
Property CasingEnum ('camelCase', 'snake_case', 'preserve')

Normaliza claves JSON a identificadores camelCase de PHP conservando el mapeo con los datos de origen.

Por defecto: camelCase
DateTime DetectionBoolean

Detecta cadenas con marca temporal ISO 8601 y las tipifica automáticamente como instancias de \DateTimeImmutable.

Por defecto: true

Consejos profesionales y mejores prácticas

Hidratación Recursiva de DTOs Anidados

Al mapear estructuras JSON anidadas o listas de objetos hijos, utilice array_map() dentro de fromArray() para invocar de forma recursiva y segura el hidratador estático de cada DTO hijo.

Al declarar readonly class en PHP 8.2

Al declarar readonly class en PHP 8.2, todas las propiedades de instancia adoptan automáticamente el modificador readonly, eliminando mutaciones accidentales y garantizando la semántica de Value Object.

Para colecciones con valores nulos o

Para colecciones con valores nulos o tipos mixtos, aplique tipos de unión de PHP 8.0+ (p. ej., string|int|null) y anotaciones PHPDoc (/** @var list<UserDto> */) para superar análisis estáticos en PHPStan y Psalm a Nivel 8+.

Combine la promoción de constructor

Combine la promoción de constructor con atributos como #[SerializedName('clave')] de Symfony o #[MapInputName] de Spatie para desacoplar el contrato JSON externo de los nombres de dominio internos.

Errores comunes y solución de problemas

Error fatal en tiempo de ejecución 'Cannot modify readonly property'

Las propiedades readonly de PHP 8.2 no pueden modificarse tras la ejecución del constructor. Emplee métodos inmutables de clonación (withers) o suministre todos los valores en la inicialización dentro de fromArray().

Fallo al desempaquetar arreglos asociativos anidados en el constructor

Evite pasar directamente arrays asociativos a parámetros tipados de clases hijas; utilice siempre el método estático fromArray() correspondiente para su correcta instanciación.

Excepción DateMalformedStringException al parsear fechas en PHP 8.3+

Compruebe el formato de la cadena antes de crear new \DateTimeImmutable(), o capture la excepción en un bloque try-catch asignando un valor nulo ?\DateTimeImmutable de respaldo.

Preguntas frecuentes (FAQ)

¿Cuáles son las ventajas de las clases readonly de PHP 8.2 para DTOs?▼

Impiden cualquier mutación de propiedades tras la instanciación y bloquean por completo la adición de propiedades dinámicas. Esto otorga inmutabilidad total, seguridad de hilos en entornos concurrentes (Swoole, RoadRunner) y elimina la necesidad de copias defensivas.

¿Cómo reduce el código repetitivo la promoción de propiedades en constructor?▼

En lugar de declarar propiedades de clase, argumentos del constructor y asignaciones manuales ($this->prop = $prop), la promoción agrupa visibilidad, tipo, inmutabilidad y valores predeterminados en una sola firma de __construct(), recortando más del 60% de líneas.

¿Se pueden generar DTOs compatibles con Symfony Serializer o Laravel Spatie Data?▼

Sí. El generador permite incorporar atributos nativos como #[SerializedName] de Symfony o #[MapInputName] de Spatie Data para mapear cargas útiles en snake_case con propiedades de objeto en camelCase sin fricción.

¿Cómo gestiona fromArray() los campos faltantes o nulos en el JSON?▼

Examina todas las muestras JSON para identificar claves opcionales o nulas, aplicando tipos anulables (?string $campo = null) y el operador de fusión null ($data['campo'] ?? null) para prevenir advertencias de claves indefinidas.

¿Se envía la carga JSON a algún servidor externo durante la generación?▼

No. Todo el análisis sintáctico de JSON, la deducción del árbol AST y la generación del código PHP se llevan a cabo 100% en la memoria de su navegador mediante JavaScript, garantizando absoluta privacidad de sus datos.

Herramientas y utilidades relacionadas

Todas las herramientas →