Free & open source — no account required
Free & open source — no account required
This technical guide provides an in-depth analysis of the json to php dto engine, best practices for implementation, and data security standards.
PHP 8's constructor promotion and readonly properties make DTOs (Data Transfer Objects) significantly cleaner than the old getter/setter pattern. When you receive a JSON payload from an API or client request, generating the DTO class structure from the JSON shape gives you a typed, immutable value object that makes your controllers and services easier to reason about.
// Input JSON (API request body)
{
"order_id": "ord_8821",
"customer_email": "buyer@example.com",
"total_amount": 149.99,
"currency": "USD",
"item_count": 3,
"is_gift": false,
"gift_message": null
}
// Generated PHP DTO
<?php
// PHP version 8.1+ required
class Root
{
public function __construct(
private string $order_id,
private string $customer_email,
private float $total_amount,
private string $currency,
private float $item_count,
private bool $is_gift,
private ?string $gift_message,
) {}
public function getOrderId(): string { return $this->order_id; }
public function getCustomerEmail(): string { return $this->customer_email; }
public function getTotalAmount(): float { return $this->total_amount; }
public function getCurrency(): string { return $this->currency; }
public function getItemCount(): float { return $this->item_count; }
public function getIsGift(): bool { return $this->is_gift; }
public function getGiftMessage(): ?string { return $this->gift_message; }
}
PHP 8.2 added readonly at the class level, making all promoted properties automatically readonly. This is the cleanest DTO pattern available:
<?php
declare(strict_types=1);
// PHP 8.2+: readonly class makes all properties immutable automatically
readonly class OrderDto
{
public function __construct(
public string $orderId,
public string $customerEmail,
public float $totalAmount,
public string $currency,
public int $itemCount, // int not float for counts
public bool $isGift,
public ?string $giftMessage,
) {}
public static function fromArray(array $data): self
{
return new self(
orderId: $data['order_id'],
customerEmail: $data['customer_email'],
totalAmount: (float) $data['total_amount'],
currency: $data['currency'],
itemCount: (int) $data['item_count'],
isGift: (bool) $data['is_gift'],
giftMessage: $data['gift_message'] ?? null,
);
}
}
// Usage in a controller
$dto = OrderDto::fromArray(json_decode($request->getContent(), true));
echo $dto->customerEmail; // public readonly — readable, not writable
// $dto->customerEmail = 'x'; // Fatal error: Cannot modify readonly property
<?php
// Option 1: Laravel Form Request (built-in validation + DTO in one)
use Illuminate\Foundation\Http\FormRequest;
class StoreOrderRequest extends FormRequest
{
public function rules(): array
{
return [
'order_id' => ['required', 'string'],
'customer_email' => ['required', 'email'],
'total_amount' => ['required', 'numeric', 'min:0'],
'currency' => ['required', 'string', 'size:3'],
'item_count' => ['required', 'integer', 'min:1'],
'is_gift' => ['boolean'],
'gift_message' => ['nullable', 'string', 'max:500'],
];
}
}
// In controller: Laravel injects the validated DTO automatically
class OrderController extends Controller
{
public function store(StoreOrderRequest $request): JsonResponse
{
$validated = $request->validated(); // array, already validated
$order = $this->orderService->create($validated);
return response()->json($order, 201);
}
}
// Option 2: Spatie Laravel-Data (generates DTOs with validation + casting)
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Attributes\Validation\Email;
class OrderData extends Data
{
public function __construct(
public readonly string $orderId,
#[Email]
public readonly string $customerEmail,
public readonly float $totalAmount,
public readonly string $currency,
public readonly int $itemCount,
public readonly bool $isGift = false,
public readonly ?string $giftMessage = null,
) {}
}
// Auto-maps from request: OrderData::from($request)
<?php
readonly class OrderDto
{
public function __construct(
public string $orderId,
public string $customerEmail,
public float $totalAmount,
public string $currency,
public int $itemCount,
public bool $isGift,
public ?string $giftMessage,
) {}
public static function fromJson(string $json): self
{
$data = json_decode($json, associative: true, flags: JSON_THROW_ON_ERROR);
return self::fromArray($data);
}
public static function fromArray(array $data): self
{
return new self(
orderId: $data['order_id'] ?? throw new \InvalidArgumentException('order_id required'),
customerEmail: filter_var($data['customer_email'], FILTER_VALIDATE_EMAIL)
?: throw new \InvalidArgumentException('invalid email'),
totalAmount: (float) ($data['total_amount'] ?? 0),
currency: strtoupper($data['currency'] ?? 'USD'),
itemCount: (int) ($data['item_count'] ?? 0),
isGift: (bool) ($data['is_gift'] ?? false),
giftMessage: $data['gift_message'] ?? null,
);
}
public function toArray(): array
{
return [
'order_id' => $this->orderId,
'customer_email' => $this->customerEmail,
'total_amount' => $this->totalAmount,
'currency' => $this->currency,
'item_count' => $this->itemCount,
'is_gift' => $this->isGift,
'gift_message' => $this->giftMessage,
];
}
}
What's the difference between constructor promotion and regular properties? Constructor promotion (public function __construct(private string $name)) declares the property and assigns it in one step — no separate private string $name; declaration needed. Available since PHP 8.0. Combined with readonly (PHP 8.1) or readonly class (PHP 8.2), it's the most concise DTO pattern.
Should I use float or string for monetary values? Use string or a Money value object for monetary amounts. Floating-point arithmetic on currency values causes rounding errors (0.1 + 0.2 !== 0.3 in floating-point). Store and compute money as integers (cents) or use bcmath functions with string representations.
Does this work with PHP 7? Constructor promotion is PHP 8.0+; readonly properties are PHP 8.1+; readonly classes are PHP 8.2+. For PHP 7, you need explicit property declarations, constructor assignment, and getters.
Is my JSON sent to a server? No. TypeMorph runs entirely in your browser — none of your data leaves your machine.
Is the processing local-only?
Absolutely. TypeMorph operates entirely within your browser's sandbox. We use Web Workers for high-performance computation without ever transmitting your JSON, SQL, or API data to a remote server.
Can I use this for enterprise projects?
Yes. The tool is designed for professional software engineers who require GDPR compliance and data privacy. It is trusted by developers at top-tier startups and financial institutions.