Introduzione
Quando si parla di eccezioni e gestione degli errori in PHP, spesso ci si concentra solo sul classico blocco try-catch. In realtà, uno degli aspetti più utili e pratici è capire come distinguere tra errore tecnico ed errore di validazione, soprattutto quando i dati arrivano da form, API, file JSON o richieste HTTP.
Questo tutorial affronta un sotto-argomento molto concreto: validare i dati in ingresso e trasformare i problemi di input in eccezioni controllate. È un approccio estremamente utile perché permette di:
- evitare bug nascosti causati da dati incompleti o non corretti;
- separare la logica di validazione dalla logica di business;
- gestire gli errori in modo coerente e leggibile;
- produrre messaggi utili per sviluppatori e utenti finali.
In pratica, invece di verificare ogni campo con decine di if sparsi nel codice, possiamo centralizzare i controlli in una funzione o in una classe dedicata e lanciare eccezioni quando i dati non rispettano le regole attese.
Codice completo
<?php
declare(strict_types=1);
/**
* Eccezione personalizzata per errori di validazione.
* Non è obbligatoria, ma rende il codice più chiaro.
*/
class ValidationException extends Exception
{
}
/**
* Valida i dati di registrazione ricevuti da un form o da una API.
*
* Regole:
* - nome: obbligatorio, almeno 3 caratteri
* - email: obbligatoria, formato valido
* - età: obbligatoria, intero maggiore o uguale a 18
*/
function validateRegistrationData(array $data): array
{
$errors = [];
// Controllo nome
if (!isset($data[´name´]) || trim($data[´name´]) === ´´) {
$errors[] = ´Il campo nome è obbligatorio.´;
} elseif (mb_strlen(trim($data[´name´])) < 3) {
$errors[] = ´Il nome deve contenere almeno 3 caratteri.´;
}
// Controllo email
if (!isset($data[´email´]) || trim($data[´email´]) === ´´) {
$errors[] = ´Il campo email è obbligatorio.´;
} elseif (!filter_var($data[´email´], FILTER_VALIDATE_EMAIL)) {
$errors[] = ´L’email inserita non è valida.´;
}
// Controllo età
if (!isset($data[´age´]) || $data[´age´] === ´´) {
$errors[] = ´Il campo età è obbligatorio.´;
} elseif (filter_var($data[´age´], FILTER_VALIDATE_INT) === false) {
$errors[] = ´L’età deve essere un numero intero.´;
} elseif ((int)$data[´age´] < 18) {
$errors[] = ´Devi avere almeno 18 anni per registrarti.´;
}
// Se ci sono errori, li trasformiamo in eccezione
if (!empty($errors)) {
throw new ValidationException(implode(´ ´, $errors));
}
// Restituiamo i dati puliti e normalizzati
return [
´name´ => trim($data[´name´]),
´email´ => trim($data[´email´]),
´age´ => (int) $data[´age´],
];
}
/**
* Simula il salvataggio di un utente.
* In un progetto reale qui potresti chiamare un repository o un database.
*/
function registerUser(array $data): void
{
try {
$validData = validateRegistrationData($data);
// Simulazione di operazione successiva alla validazione
echo ´Utente registrato con successo: ´ . $validData[´name´] . ´ (´ . $validData[´email´] . ´)´ . PHP_EOL;
} catch (ValidationException $e) {
// Errore di input: messaggio utile e controllato
echo ´Errore di validazione: ´ . $e->getMessage() . PHP_EOL;
} catch (Throwable $e) {
// Qualsiasi altro problema inatteso
echo ´Errore generico: ´ . $e->getMessage() . PHP_EOL;
}
}
// Esempio 1: dati validi
registerUser([
´name´ => ´Mario Rossi´,
´email´ => ´[email protected]´,
´age´ => ´28´,
]);
echo PHP_EOL;
// Esempio 2: dati non validi
registerUser([
´name´ => ´Al´,
´email´ => ´email-non-valida´,
´age´ => ´16´,
]); Spiegazione
Nel codice abbiamo separato due concetti fondamentali:
- validazione: controlla se i dati rispettano le regole richieste;
- gestione delle eccezioni: decide cosa fare quando la validazione fallisce.
1. Eccezione personalizzata
La classe ValidationException estende Exception. Questo ci permette di distinguere in modo preciso gli errori di validazione dagli altri errori del programma. È una scelta utile perché rende il codice più leggibile e più semplice da mantenere.
2. Funzione di validazione
La funzione validateRegistrationData() riceve un array e controlla tre campi:
- name: deve esistere, non essere vuoto e avere almeno 3 caratteri;
- email: deve esistere e passare il filtro FILTER_VALIDATE_EMAIL;
- age: deve esistere, essere un intero valido e avere un valore minimo di 18.
Invece di fermarci al primo errore, raccogliamo tutti i problemi in un array $errors. Questo è molto utile lato UX, perché l’utente riceve un elenco completo dei campi da correggere, senza dover ripetere più volte l’invio del form.
3. Lancio dell’eccezione
Se l’array $errors non è vuoto, lanciamo una ValidationException con un messaggio unico costruito tramite implode(). In questo modo il chiamante può intercettare il problema con un blocco try-catch.
4. Normalizzazione dei dati
Se la validazione va a buon fine, la funzione restituisce un array pulito:
- nome con spazi rimossi;
- email normalizzata;
- età convertita in intero.
Questo è un passaggio importante: non basta verificare i dati, bisogna anche prepararli per l’uso successivo.
5. Gestione finale con try-catch
La funzione registerUser() prova a validare i dati e poi simula la registrazione. Se la validazione fallisce, intercetta ValidationException e mostra un messaggio chiaro. Se invece accade qualcosa di imprevisto, il blocco catch (Throwable $e) intercetta anche errori non legati alla validazione.
Questa distinzione è molto importante in applicazioni reali: un dato sbagliato non è la stessa cosa di un bug interno o di un problema di infrastruttura.
Best practice
- Non usare le eccezioni per tutto: le eccezioni sono perfette per gestire situazioni eccezionali o invalidità del flusso, non per ogni semplice controllo banale.
- Separare validazione e business logic: meglio avere funzioni o classi dedicate alla validazione, così il codice resta più pulito.
- Restituire dati normalizzati: dopo la validazione, converti i valori nel formato corretto, ad esempio stringhe pulite o interi.
- Raccogliere più errori insieme: quando possibile, mostra tutti i problemi in una volta sola invece di interrompere il flusso al primo errore.
- Usare eccezioni personalizzate: aiutano a distinguere le categorie di errore e rendono più chiaro il debug.
- Non esporre dettagli tecnici all’utente finale: nei messaggi pubblici evita stack trace, query SQL o informazioni sensibili.
Riepilogo
Gestire bene le eccezioni in PHP non significa solo scrivere blocchi try-catch. Un approccio professionale parte dalla qualità dei dati in ingresso. Quando validi correttamente input provenienti da form, API o file, riduci gli errori a valle e rendi il sistema più affidabile.
In questo tutorial abbiamo visto come:
- creare un’eccezione personalizzata per la validazione;
- controllare i dati in ingresso con regole chiare;
- trasformare gli errori di input in eccezioni gestibili;
- separare validazione, normalizzazione e logica applicativa.
Questo approccio è molto utile in progetti reali, specialmente quando lavori con form di registrazione, endpoint REST, importazioni dati o qualunque scenario in cui l’input non sia completamente affidabile.
Approfondisci con risorse ufficiali
- PHP Manual - Exceptions: https://www.php.net/manual/en/language.exceptions.php
- PHP Manual - Throwable: https://www.php.net/manual/en/class.throwable.php
- PHP Manual - filter_var(): https://www.php.net/manual/en/function.filter-var.php
- PHP Manual - strict_types: https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict
- PHP Manual - mb_strlen(): https://www.php.net/manual/en/function.mb-strlen.php
