← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Data Transfer Object (DTO)

quality PHP 8.0+ Intermediate

Also Known As

DTO data object transfer object

TL;DR

A simple object that carries data between layers or systems with no business logic — reducing coupling between layers and making data contracts explicit.

Explanation

DTOs carry data without behaviour — they are glorified structs. They decouple layers: a controller accepts a CreateUserDTO from the HTTP layer, passes it to the domain without exposing HTTP-specific types, and the domain returns a UserDTO to the controller without exposing internal entities. In PHP, DTOs are implemented as readonly classes (PHP 8.2), value objects, or simple classes with typed properties and constructor promotion.

Common Misconception

DTOs and Value Objects are the same thing — Value Objects have domain meaning and validate their own state; DTOs are layer-crossing containers with no validation logic.

Why It Matters

Without DTOs, controllers pass raw arrays or HTTP request objects into domain services, coupling domain logic to HTTP infrastructure and making it untestable in isolation.

Common Mistakes

  • Adding business logic to a DTO — it should be a data container; logic belongs in the domain.
  • Using the same DTO for input and output — input DTOs carry unvalidated data; output DTOs carry validated results.
  • Not using readonly properties for DTOs — a mutable DTO can be changed after construction, losing the data-snapshot guarantee.
  • Using arrays instead of DTOs — arrays lose type information and require constant isset() checks.

Avoid When

  • The DTO simply mirrors an entity one-to-one with no transformation — it adds a class for no benefit.
  • Using DTOs as mutable bags that accumulate logic over time — keep them dumb data carriers.
  • Passing DTOs across process boundaries without versioning — unversioned DTOs break when fields change.

When To Use

  • Transferring data across layer boundaries (controller → service → repository) without leaking domain objects.
  • API request and response shapes that differ from internal domain models.
  • Type-safe alternatives to associative arrays when passing structured data between methods.
  • Decoupling serialisation concerns from domain logic — DTOs can be serialised freely without affecting entities.

Code Examples

✗ Vulnerable
// No DTO — domain service receives HTTP request:
class UserService {
    public function create(Request $request): User { // Coupled to HTTP!
        return User::create([
            'name' => $request->input('name'),
            'email' => $request->input('email'),
        ]);
    }
}
✓ Fixed
// DTO decouples HTTP from domain:
readonly class CreateUserDTO {
    public function __construct(
        public string $name,
        public string $email,
    ) {}
}

class UserService {
    public function create(CreateUserDTO $dto): User {
        return User::create(['name' => $dto->name, 'email' => $dto->email]);
    }
}

Added 15 Mar 2026
Edited 25 Mar 2026
Views 49
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 3 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 3 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 3 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 14 Perplexity 11 Google 6 Unknown AI 3 Ahrefs 3 ChatGPT 2 Majestic 1 Qwen 1
crawler 39 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Low
⚡ Quick Fix
Use readonly constructor promotion for DTOs — public function __construct(public readonly string $email, public readonly int $age) {} — zero boilerplate, immutable by default
📦 Applies To
PHP 8.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Mutable DTO with public setters; passing associative arrays instead of typed DTOs across layer boundaries
Auto-detectable: ✗ No phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class

✓ schema.org compliant