Table of Contents
3. Objects & Data Transfer Objects (DTOs) — Representing Data in Modern PHP
Why this matters
Modern PHP uses objects not just for behavior, but for clarity of data.
In contrast, AI often generates arrays everywhere — associative arrays for input, output, configuration, responses, and even domain data (see DTO example below).
But arrays:
- have no structure
- have no guarantees
- are easy to misuse
- hide mistakes until runtime
DTOs solve this by giving shape to our data.
Understanding when to use objects — and when a DTO is the right tool — helps us keep our code predictable, explicit, and easy to review.
1. Objects represent behavior + state
A traditional object bundles:
- state (properties)
- behavior (methods)
Example:
class User { public function __construct( public string $name, public string $email, ) {} public function greet(): string { return "Hello, {$this->name}"; } }
Objects are ideal when:
- the data has meaning
- the data has rules
- the data has behavior
- the data belongs to a domain concept
AI often generates objects with no behavior
— which is a sign that a DTO might be more appropriate.
2. DTOs represent pure data
A Data Transfer Object is a simple, structured container for data — no behavior, no logic, no side effects.
Example:
class UserData { public function __construct( public string $name, public string $email, ) {} }
| DTOs are ideal when we | - are passing data between layers, - want type safety, - want predictable structure, - want to avoid “stringly‑typed” arrays |
DTOs make our code self‑documenting.
3. Why DTOs are better than arrays
Associative arrays are flexible — too flexible.
Arrays:
- allow missing keys
- allow extra keys
- allow wrong types
- allow silent failures
- hide mistakes
DTOs:
- enforce structure
- enforce types
- make intent visible
- fail early and predictably
- integrate cleanly with static analysis
AI often defaults to arrays because
they’re easy to generate.
Our mental model helps us replace them with DTOs
where structure matters.
4. Promotion makes DTOs effortless
PHP 8 introduced constructor property promotion:
class ProductData { public function __construct( public int $id, public string $name, public float $price, ) {} }
This turns DTOs into a first‑class citizen of modern PHP:
- minimal boilerplate
- clear structure
- strong typing
- easy to read
- easy to maintain
This is one of the most important modern PHP idioms.
5. DTOs are not entities
A DTO:
- has no behavior
- has no identity
- has no lifecycle
- is not tied to persistence
An entity:
- has identity
- has rules
- has behavior
- belongs to a domain
AI often confuses these two
— generating DTOs where entities belong, or vice‑versa.
Our understanding helps us keep the architecture clean.
6. When to use a DTO
Use a DTO when we need:
- structured input
- structured outputAPI request/response objects
- form data
- query results
- configuration objects
- data passed between layers
DTOs shine when we want clarity without behavior.
7. When not to use a DTO
Avoid DTOs when:
- the data has rules
- the data has invariants
- the data has behavior
- the data belongs to a domain concept
In those cases, use a real object
— an entity or value object.
8. When AI gets this wrong
AI often defaults to associative arrays for everything — input, output, configuration, even domain data. This works, but it hides structure and makes mistakes harder to see. Our mental model helps us notice when an array should really be a DTO, especially in places where shape, clarity, or type safety matter.
Summary
Modern PHP uses objects for behavior and DTOs for structure.
DTOs give us:
- clarity
- type safety
- predictable shape
- self‑documenting code
- fewer runtime surprises
Once we internalize this, we can immediately see when AI‑generated code is relying too heavily on arrays — or using objects where a DTO would be cleaner.
