Introduzione
Quando si parla di eccezioni in PHP, spesso ci si concentra su try-catch, su classi personalizzate o su logger dedicati. Un aspetto molto utile, però, è capire come gestire correttamente gli errori nel livello di accesso ai dati, soprattutto quando si lavora con un repository o con una classe che incapsula le operazioni su database o API.
In questo tutorial vediamo un caso pratico: un repository PHP che legge un utente da un database e trasforma gli errori tecnici in eccezioni significative. L’obiettivo è evitare che il resto dell’applicazione debba conoscere i dettagli del database, delle query o dei messaggi di errore PDO. In questo modo il codice diventa più pulito, testabile e facile da mantenere.
Questo approccio è molto usato nei progetti moderni: il repository si occupa dei dati, mentre il livello superiore decide come reagire agli errori. È una soluzione pratica perché separa le responsabilità e riduce il rischio di spargere controlli confusi in tutta l’applicazione.
Codice completo
<?php
declare(strict_types=1);
/**
* Esempio didattico:
* - Repository che legge un utente dal database
* - Eccezioni specifiche per errori di dominio e di accesso ai dati
* - Gestione centralizzata degli errori nel livello applicativo
*/
class UserNotFoundException extends RuntimeException {}
class DataAccessException extends RuntimeException {}
final class UserRepository
{
public function __construct(
private PDO $pdo
) {}
public function findById(int $id): array
{
try {
$sql = "SELECT id, name, email FROM users WHERE id = :id";
$stmt = $this- Spiegazione
Il punto chiave di questo esempio è la separazione tra errore tecnico e errore di dominio.
1. UserNotFoundException
Questa eccezione segnala una situazione normale dal punto di vista applicativo: l’utente richiesto non esiste. Non è un errore del database, ma una condizione che il programma deve saper gestire. Per questo è utile avere un’eccezione dedicata.
2. DataAccessException
Questa eccezione rappresenta un problema tecnico: query fallita, connessione non disponibile, errore PDO, problemi di configurazione. Invece di lasciare che il resto del codice riceva un messaggio grezzo del database, lo convertiamo in un messaggio più pulito e coerente.
3. Repository
La classe UserRepository incapsula tutta la logica di accesso ai dati. Il metodo findById():
- prepara la query;
- esegue la ricerca;
- controlla se l’utente esiste;
- trasforma eventuali errori PDO in una eccezione più significativa.
Questo è un grande vantaggio: il resto dell’applicazione non deve sapere nulla di prepare, bindValue o fetch. Riceve solo un risultato valido oppure un’eccezione chiara.
4. Servizio applicativo
La classe UserService rappresenta un livello più alto. In questo esempio non aggiunge logica, ma in un progetto reale potrebbe validare permessi, combinare più repository o orchestrare operazioni complesse. Il servizio non deve occuparsi dei dettagli SQL.
5. Gestione finale degli errori
Nel blocco try-catch esterno, l’applicazione decide come reagire:
- se l’utente non esiste, mostra un messaggio chiaro;
- se c’è un problema tecnico, mostra un messaggio generico;
- se avviene un errore imprevisto, viene intercettato da Throwable.
Questa struttura è molto utile perché evita di mostrare dettagli sensibili come SQL, credenziali o stack trace all’utente finale.
Best practice
- Non lanciare eccezioni generiche senza contesto: una classe come
DataAccessExceptionrende il codice più leggibile e gestibile. - Separare errori di dominio e tecnici: un record mancante non è lo stesso problema di un database offline.
- Usare PDO con ERRMODE_EXCEPTION: è il modo più affidabile per trasformare gli errori SQL in eccezioni PHP.
- Non esporre dettagli interni all’utente: i messaggi tecnici vanno loggati, non stampati in pagina.
- Usare catch mirati: catturare prima le eccezioni più specifiche e solo alla fine
Throwable. - Non mettere troppa logica nel repository: il repository deve leggere e scrivere dati, non prendere decisioni di business complesse.
- Propagare il precedente errore: usare il parametro
previousaiuta nel debugging e conserva la causa originale.
Riepilogo
Gestire le eccezioni nel livello repository è una pratica molto efficace in PHP. Ti permette di:
- isolare i dettagli tecnici di accesso ai dati;
- distinguere chiaramente tra errori applicativi e errori infrastrutturali;
- scrivere codice più pulito e testabile;
- mostrare messaggi più comprensibili all’utente;
- mantenere un controllo coerente sugli errori in tutta l’applicazione.
In sintesi, non basta “catturare un’eccezione”: bisogna decidere dove catturarla, come trasformarla e quale significato dare all’errore nel contesto dell’applicazione.
Approfondisci con risorse ufficiali
- PHP Manual - Exceptions: https://www.php.net/manual/it/language.exceptions.php
- PHP Manual - PDO: https://www.php.net/manual/it/book.pdo.php
- PHP Manual - PDO::prepare: https://www.php.net/manual/it/pdo.prepare.php
- PHP Manual - Throwable: https://www.php.net/manual/it/class.throwable.php
- PHP Manual - PDOException: https://www.php.net/manual/it/class.pdoexception.php
