← Torna agli articoli
Architettura PHP e pattern di progettazione

Cos'è un DTO in PHP e perché ne hai bisogno?

Scopri cos'è un Data Transfer Object (DTO) in PHP, perché è importante per la sicurezza dei tipi e l'architettura pulita, e come implementarlo con le funzionalità moderne di PHP 8.

Cos'è un DTO in PHP e perché ne hai bisogno?
Articolo in evidenza ↗

Cos'è un DTO in PHP e perché ne hai bisogno?

Quando si costruiscono applicazioni PHP, gli sviluppatori affrontano costantemente la sfida di passare dati tra diversi livelli di un'applicazione: controller, servizi, repository e viste. Un anti-pattern comune è passare array grezzi o oggetti stdClass, il che porta a contratti poco chiari, bug nascosti e refactoring difficile. È qui che entrano in gioco i Data Transfer Objects (DTO).

Cos'è un DTO?

Un DTO (Data Transfer Object, oggetto di trasferimento dati) è un oggetto semplice il cui unico scopo è trasportare dati tra processi o livelli di un'applicazione. Non contiene logica di business, regole di validazione o query al database — solo proprietà e metodi per accedervi.

Il termine è stato reso popolare da Martin Fowler nel suo libro Patterns of Enterprise Application Architecture. Nel mondo PHP, i DTO sono diventati ampiamente adottati con l'ascesa del Domain-Driven Design (DDD) e dell'architettura pulita.

Perché hai bisogno dei DTO?

Usare i DTO invece di array o oggetti generici offre diversi vantaggi importanti:

  • Sicurezza dei tipi — i DTO hanno proprietà rigorosamente tipizzate, il che individua gli errori in anticipo e migliora l'autocompletamento dell'IDE.
  • Contratti chiari — un DTO definisce esplicitamente quali dati trasporta, a differenza di un semplice array con chiavi sconosciute.
  • Immutabilità — i DTO possono essere resi di sola lettura, impedendo la modifica accidentale dei dati mentre viaggiano attraverso il sistema.
  • Incapsulamento — la struttura dei dati è separata dalla logica di business, mantenendo il codice pulito e focalizzato.
  • Refactoring più semplice — cambiare la struttura di un DTO è una modifica in un unico punto, non una caccia attraverso decine di accessi agli array.
  • Auto-documentazione — la classe stessa descrive la forma dei dati.

Un semplice esempio di DTO in PHP

Creiamo un DTO di base per un utente:

<?php declare(strict_types=1); final class UserDTO { public function __construct( public readonly int $id, public readonly string $name, public readonly string $email, public readonly int $age, ) { } }

Grazie alle proprietà readonly di PHP 8.1+ e alla promozione del costruttore, questo DTO è conciso, immutabile e sicuro dal punto di vista dei tipi.

Usare un DTO nella pratica

Ecco come potresti usare un DTO quando restituisci dati da un repository:

<?php final class UserRepository { public function findById(int $id): ?UserDTO { $row = $this->db->fetchOne('SELECT * FROM users WHERE id = ?', [$id]); if ($row === null) { return null; } return new UserDTO( id: (int) $row['id'], name: $row['name'], email: $row['email'], age: (int) $row['age'], ); } }

Ora il codice chiamante sa esattamente quali dati riceve:

<?php $user = $repository->findById(42); if ($user !== null) { echo $user->name; // L'IDE sa che è una stringa echo $user->email; // L'IDE sa che è una stringa }

DTO vs. Value Object vs. Entity

È importante non confondere i DTO con altri pattern:

  • DTO — trasporta dati, nessun comportamento, nessuna identità.
  • Value Object — immutabile, definito dai suoi valori, può contenere comportamento (ad esempio, Money, Email).
  • Entity — ha un'identità unica e un ciclo di vita, contiene logica di business.

Mappare array in DTO

Nelle applicazioni reali, spesso è necessario costruire un DTO da un array, come il payload di una richiesta. Un approccio comune è un metodo factory statico:

<?php final class CreateUserDTO { public function __construct( public readonly string $name, public readonly string $email, public readonly int $age, ) { } public static function fromArray(array $data): self { return new self( name: $data['name'], email: $data['email'], age: (int) $data['age'], ); } }

DTO e validazione

I DTO non dovrebbero eseguire la validazione da soli. Invece, mantieni la validazione in un livello dedicato, come una form request o un servizio di validazione. Il DTO viene creato solo dopo che i dati sono stati validati.

<?php $data = $request->getParsedBody(); $validator->validate($data, [ 'name' => 'required|string', 'email' => 'required|email', 'age' => 'required|integer|min:18', ]); $dto = CreateUserDTO::fromArray($data);

Quando i DTO potrebbero essere eccessivi

I DTO non sono sempre necessari. In piccoli script o prototipi, l'uso di array può essere perfettamente appropriato. Introdurre i DTO ha senso quando:

  • La tua applicazione ha più livelli con confini chiari.
  • I dati vengono passati attraverso confini di moduli o servizi.
  • Hai bisogno di sicurezza dei tipi e manutenibilità a lungo termine.
  • Più consumatori si affidano alla stessa struttura dati.

Migliori pratiche per i DTO in PHP

  • Rendili immutabili — usa proprietà readonly o proprietà private con getter.
  • Mantienili piccoli — un DTO dovrebbe rappresentare un concetto chiaro.
  • Nessuna logica di business — sposta qualsiasi logica in servizi o oggetti di dominio.
  • Usa tipi strict — dichiara strict_types=1 in ogni file DTO.
  • Fornisci metodi factory come fromArray() o fromRequest() per una costruzione comoda.
  • Evita i setter — un DTO dovrebbe essere creato una volta e mai modificato.

Conclusione

I DTO sono un pattern semplice ma potente che porta chiarezza, sicurezza dei tipi e manutenibilità alle applicazioni PHP. Definiscono contratti espliciti tra i livelli, riducono i bug causati da array debolmente tipizzati e rendono il refactoring notevolmente più semplice. Sebbene aggiungano un po' di boilerplate, i benefici a lungo termine in progetti medi e grandi superano di gran lunga il costo. Inizia in piccolo: introduci i DTO dove i dati attraversano i confini dei livelli, e sentirai rapidamente la differenza nella qualità del codice.

Prova a rifattorizzare uno dei tuoi flussi di dati basati su array in un DTO oggi stesso — il tuo io futuro ti ringrazierà.

Tecnologie e argomenti

Tag dell'articolo

Nessun articolo corrisponde a questi filtri.

Hai un progetto o un'idea da discutere?

Parliamone ↗