Introduzione
Una delle novità più utili introdotte nelle versioni recenti di PHP è il miglioramento del sistema dei tipi. Se in passato PHP era spesso usato in modo “dinamico” e poco controllato, oggi il linguaggio offre strumenti molto più rigorosi per descrivere i dati attesi da una funzione, da un metodo o da una proprietà.
In questo tutorial ci concentriamo su un sotto-argomento pratico e molto usato nei progetti reali: union types e dichiarazioni di tipo più espressive. Questo permette di scrivere codice più leggibile, più sicuro e con meno controlli manuali sparsi nel progetto.
Vedremo come usare i tipi per accettare più formati di input, come evitare errori comuni e come progettare API interne più chiare. È un tema fondamentale per chi lavora con PHP moderno, soprattutto in applicazioni web, API REST e servizi backend.
Codice completo
<?php
declare(strict_types=1);
class OrderRepository
{
public function findById(int|string $id): ?array
{
// Simulazione di dati recuperati dal database
$orders = [
1 => [´id´ => 1, ´customer´ => ´Mario Rossi´, ´total´ => 120.50],
2 => [´id´ => 2, ´customer´ => ´Laura Bianchi´, ´total´ => 89.90],
´A100´ => [´id´ => ´A100´, ´customer´ => ´Giulia Verdi´, ´total´ => 250.00],
];
return $orders[$id] ?? null;
}
}
class OrderService
{
public function __construct(
private OrderRepository $repository
) {}
public function getSummary(int|string $orderId): string
{
$order = $this->repository->findById($orderId);
if ($order === null) {
return "Ordine non trovato";
}
return sprintf(
"Ordine #%s: %s - Totale: €%.2f",
$order[´id´],
$order[´customer´],
$order[´total´]
);
}
public function normalizeInput(int|string|null $input): int|string
{
// Se arriva null, generiamo un valore di default
if ($input === null) {
return 0;
}
return $input;
}
}
// Esempio di utilizzo
$service = new OrderService(new OrderRepository());
echo $service->getSummary(1) . PHP_EOL;
echo $service->getSummary(´A100´) . PHP_EOL;
echo $service->getSummary(999) . PHP_EOL;
$normalized = $service->normalizeInput(null);
echo "Valore normalizzato: " . $normalized . PHP_EOL; Spiegazione
Nel codice sopra abbiamo usato union types, cioè tipi uniti da |. Questa sintassi consente di dichiarare che un parametro o un valore di ritorno può appartenere a più tipi differenti.
1. Un parametro può accettare più tipi
Nel metodo findById(int|string $id) il parametro può essere sia un intero sia una stringa. Questo è utile in molti casi reali:
- un ID numerico proveniente dal database;
- un codice alfanumerico, come un numero ordine esterno;
- un identificativo che cambia in base al contesto dell’applicazione.
Prima dei tipi uniti, spesso si era costretti a usare mixed oppure a fare controlli manuali con is_int() e is_string(). Con i tipi uniti, invece, il contratto della funzione è chiaro già nella firma.
2. Il tipo di ritorno può essere nullo
Il metodo findById() restituisce ?array, cioè un array oppure null. Questa notazione è equivalente a array|null, ma è molto comune nella forma abbreviata.
È una scelta molto pratica quando una ricerca può fallire. Invece di restituire un valore fittizio o generare un errore, il metodo comunica esplicitamente che l’elemento potrebbe non esistere.
3. strict_types migliora il controllo
La direttiva declare(strict_types=1); rende PHP più rigoroso nella gestione dei tipi. Questo significa che il motore non farà conversioni implicite troppo permissive in molti casi.
Per esempio, se una funzione accetta un intero, non è bene passare una stringa casuale sperando che PHP la converta automaticamente. Con i tipi rigidi, gli errori emergono subito e il codice diventa più affidabile.
4. Perché è utile nei progetti reali
In un’applicazione vera, i tipi aiutano a:
- ridurre bug dovuti a dati inattesi;
- documentare il comportamento del codice senza commenti superflui;
- facilitare il refactoring;
- migliorare l’autocompletamento negli editor moderni;
- rendere più semplice la manutenzione da parte di altri sviluppatori.
Best practice
Usare i tipi in PHP è molto utile, ma va fatto con criterio. Ecco alcune buone pratiche da seguire.
- Usa union types solo quando servono davvero: se una funzione dovrebbe accettare un solo tipo, evita di allargare inutilmente la firma.
- Preferisci tipi specifici a mixed: mixed è comodo, ma riduce il valore del controllo statico.
- Gestisci esplicitamente i valori null: non lasciare che il null si propaghi senza controllo.
- Combina i tipi con eccezioni chiare: quando un valore non è valido, spesso è meglio lanciare un’eccezione ben descritta.
- Usa declare(strict_types=1) nei file applicativi: aiuta a prevenire conversioni indesiderate.
- Documenta il significato semantico del tipo: ad esempio, se accetti int|string, chiarisci se la stringa deve essere numerica o alfanumerica.
Un errore comune è usare union types per “coprire tutto”. Ad esempio, dichiarare int|string|float|bool su un parametro spesso indica che la responsabilità del controllo è stata spostata troppo lontano. In questi casi conviene ripensare la progettazione dell’API.
Un’altra buona pratica è mantenere coerente il tipo tra input, logica interna e output. Se un metodo accetta un identificativo come stringa alfanumerica, non dovrebbe restituirlo improvvisamente come intero senza una ragione precisa.
Riepilogo
Le novità recenti di PHP hanno reso il linguaggio molto più robusto e adatto allo sviluppo professionale. I union types sono una delle aggiunte più pratiche perché permettono di descrivere con precisione quali tipi sono ammessi, senza dover ricorrere a controlli manuali ripetitivi.
In questo tutorial abbiamo visto:
- come dichiarare parametri con più tipi;
- come gestire valori di ritorno nullabili;
- perché strict_types è utile;
- quali vantaggi portano i tipi nel codice reale.
Se stai lavorando con PHP moderno, investire tempo nella progettazione dei tipi è una scelta vincente: il codice diventa più chiaro, più sicuro e più facile da mantenere nel tempo.
Approfondisci con risorse ufficiali
- PHP Manual - Types: documentazione ufficiale sui tipi supportati dal linguaggio.
- PHP Manual - Union Types: panoramica completa sulla sintassi int|string e sui casi d’uso.
- PHP Manual - Type Juggling: utile per capire come PHP gestisce le conversioni implicite.
- PHP Manual - Strict typing: approfondimento su declare(strict_types=1).
Se vuoi, nel prossimo tutorial posso mostrarti un altro argomento molto utile delle versioni recenti di PHP, ad esempio match expression, attributes oppure intersection types.
