Getting Started
This guide will have you generating type-safe DTOs in under 5 minutes.
What is php-collective/dto?
A code generator that creates Data Transfer Object classes from simple configuration files. Unlike runtime libraries that use reflection, this library generates plain PHP classes at build time—giving you:
- Zero runtime overhead — no reflection, no magic methods
- Perfect IDE support — real methods with full autocomplete
- Reviewable code — generated classes appear in your pull requests
Installation
composer require php-collective/dtoQuick Start
1. Create a Configuration File
Create config/dto.xml:
<?xml version="1.0" encoding="UTF-8"?>
<dtos xmlns="https://github.com/php-collective/dto">
<dto name="User">
<field name="id" type="int" required="true"/>
<field name="name" type="string" required="true"/>
<field name="email" type="string"/>
</dto>
</dtos>2. Generate the DTO
vendor/bin/dto generateThis creates src/Dto/UserDto.php with getters, setters, and array conversion methods.
3. Use It
use App\Dto\UserDto;
// Create from array (e.g., API response, form data)
$user = UserDto::createFromArray([
'id' => 1,
'name' => 'John Doe',
'email' => 'john@example.com',
]);
// Use typed getters
echo $user->getName(); // "John Doe"
echo $user->getEmail(); // "john@example.com"
// Convert back to array
$data = $user->toArray();That's it! You now have a fully typed DTO with IDE autocomplete.
Why Code Generation?
| Aspect | Code Generation | Runtime Reflection |
|---|---|---|
| Performance | Native PHP speed | 5-60x slower |
| IDE Support | Perfect (real methods) | Limited (magic) |
| Static Analysis | Works out of the box | Requires plugins |
| Code Review | See exactly what runs | Hidden behavior |
Configuration Formats
Choose your preferred format—all generate identical DTOs:
<?xml version="1.0" encoding="UTF-8"?>
<dtos xmlns="https://github.com/php-collective/dto">
<dto name="User">
<field name="name" type="string" required="true"/>
<field name="email" type="string"/>
</dto>
</dtos>use PhpCollective\Dto\Config\{Dto, Field, Schema};
return Schema::create()
->dto(Dto::create('User')->fields(
Field::string('name')->required(),
Field::string('email'),
))
->toArray();return [
'User' => [
'fields' => [
'name' => ['type' => 'string', 'required' => true],
'email' => 'string',
],
],
];User:
fields:
name:
type: string
required: true
email: stringUser:
fields:
name:
type: string
required: true
email: stringTIP
XML offers XSD validation and IDE autocomplete. PHP Builder provides the best type safety. Choose what fits your workflow.
Common Patterns
Nested DTOs
<dto name="Order">
<field name="id" type="int" required="true"/>
<field name="customer" type="Customer" required="true"/>
<field name="items" type="OrderItem[]" collection="true" singular="item"/>
</dto>
<dto name="Customer">
<field name="name" type="string"/>
<field name="email" type="string"/>
</dto>
<dto name="OrderItem">
<field name="product" type="string"/>
<field name="quantity" type="int"/>
</dto>$order = OrderDto::createFromArray($apiResponse);
// Navigate nested objects with full type safety
echo $order->getCustomer()->getName();
// Iterate collections
foreach ($order->getItems() as $item) {
echo $item->getProduct();
}Immutable DTOs
<dto name="Config" immutable="true">
<field name="apiKey" type="string" required="true"/>
<field name="timeout" type="int" defaultValue="30"/>
</dto>$config = ConfigDto::createFromArray(['apiKey' => 'secret']);
// Immutable: returns a new instance
$updated = $config->withTimeout(60);Enums
<dto name="Task">
<field name="status" type="\App\Enum\TaskStatus" required="true"/>
</dto>enum TaskStatus: string {
case Pending = 'pending';
case Done = 'done';
}
$task = TaskDto::createFromArray(['status' => 'pending']);
$task->getStatus(); // TaskStatus::PendingCLI Commands
# Generate DTOs (default command)
vendor/bin/dto generate
# Preview without writing
vendor/bin/dto generate --dry-run
# Custom paths
vendor/bin/dto generate --config-path=dto/ --src-path=app/
# Generate TypeScript interfaces
vendor/bin/dto typescript --output=frontend/types/
# Generate JSON Schema
vendor/bin/dto jsonschema --output=schemas/Deployment
Recommended: Commit Generated Code
# Install as dev dependency
composer require --dev php-collective/dto- Edit configuration
- Run
vendor/bin/dto generate - Commit generated files
- Deploy normally
Benefits: No generation on production, faster deploys, code review for DTOs.
Alternative: Generate on Deploy
composer require php-collective/dtoRun generation as part of your deployment script. Useful when DTO definitions are dynamic.
Exclude from Static Analysis
Generated code should be excluded from linters:
phpcs.xml:
<exclude-pattern>src/Dto/*</exclude-pattern>phpstan.neon:
parameters:
excludePaths:
- src/Dto/*Next Steps
- Examples — Real-world usage patterns
- Config Builder — Fluent PHP API reference
- Validation — Field constraints and rules
- TypeScript Generation — Frontend type sync