Salta al contenuto principale

Gestione degli errori e delle eccezioni in PHP

Profile picture for user luca77king

Durante lo sviluppo o l'esecuzione di un'applicazione PHP, possono verificarsi degli errori che compromettono il funzionamento del codice o la qualità del risultato. Per questo motivo, è importante gestire gli errori in maniera adeguata, sia per individuarli e correggerli, sia per prevenirli o mitigarne gli effetti. PHP offre due meccanismi principali per la gestione degli errori: la segnalazione degli errori e le eccezioni. Vediamo in cosa consistono e come si usano in PHP.

Gestione degli Errori

La segnalazione degli errori è il meccanismo che permette a PHP di comunicare al programmatore o all'utente la presenza di un errore nel codice. PHP ha diversi livelli di errori, che indicano la gravità o la natura dell'errore:

  • Notice: sono errori di basso livello, che non influiscono sul funzionamento del codice, ma che segnalano delle situazioni potenzialmente problematiche, come l'uso di variabili non definite o l'accesso a indici non esistenti di un array.
  • Warning: sono errori di medio livello, che non bloccano l'esecuzione del codice, ma che indicano delle situazioni che potrebbero causare dei risultati inaspettati o indesiderati, come l'apertura fallita di un file o la divisione per zero.
  • Fatal Error: sono errori di alto livello, che interrompono l'esecuzione del codice, e che indicano delle situazioni che impediscono il normale funzionamento dell'applicazione, come la chiamata a una funzione non esistente o la mancanza di memoria. Per configurare la segnalazione degli errori, si possono usare due funzioni: `error_reporting()` e `ini_set()`. La funzione `error_reporting()` permette di impostare il livello di errori da segnalare, tramite una costante predefinita o una combinazione di costanti con l'operatore `|`.
<?php
// Segnala solo gli errori fatali
error_reporting(E_ERROR);

// Segnala tutti gli errori tranne le notice
error_reporting(E_ALL & ~E_NOTICE);

// Segnala tutti gli errori
error_reporting(E_ALL);
?>

La funzione ini_set() permette di impostare il comportamento di PHP rispetto agli errori, tramite delle direttive di configurazione. Le principali direttive sono:

  • display_errors: se impostata a On, mostra gli errori sullo schermo; se impostata a Off, nasconde gli errori dallo schermo. Questa direttiva è utile per evitare di mostrare informazioni sensibili o inutili all’utente finale, e per facilitare il debug durante lo sviluppo.
  • log_errors: se impostata a On, registra gli errori in un file di log; se impostata a Off, non registra gli errori in un file di log. Questa direttiva è utile per tenere traccia degli errori e per analizzarli successivamente.
  • error_log: specifica il percorso del file di log in cui registrare gli errori. Se non viene specificato, il file di log è quello predefinito del sistema operativo.

Ad esempio:

<?php
// Nasconde gli errori dallo schermo
ini_set('display_errors', 'Off');

// Registra gli errori in un file di log
ini_set('log_errors', 'On');

// Imposta il file di log personalizzato
ini_set('error_log', 'errori.log');
?>

Per gestire gli errori in maniera personalizzata, si può usare la funzione set_error_handler(), che accetta come parametro il nome di una funzione definita dall’utente, che verrà invocata ogni volta che si verifica un errore. La funzione deve accettare almeno quattro parametri: il livello dell’errore, il messaggio dell’errore, il file in cui si è verificato l’errore e la linea in cui si è verificato l’errore. Ad esempio:

<?php
// Definisco la funzione per gestire gli errori
function gestisci_errori($livello, $messaggio, $file, $linea) {
  // Mostro un messaggio personalizzato
  echo "Si è verificato un errore: $messaggio<br>";
  echo "Livello: $livello<br>";
  echo "File: $file<br>";
  echo "Linea: $linea<br>";
}

// Imposto la funzione come gestore degli errori
set_error_handler('gestisci_errori');
?>

Eccezioni

Le eccezioni sono un meccanismo che permette di gestire gli errori in maniera più controllata e strutturata. Le eccezioni sono degli oggetti che rappresentano delle situazioni eccezionali o anomale che si verificano durante l’esecuzione del codice. Le eccezioni possono essere generate da PHP o dal programmatore, e possono essere catturate e gestite tramite la struttura try-catch.

La struttura try-catch consiste di due blocchi di codice: il blocco try, che contiene il codice potenzialmente soggetto a errori, e il blocco catch, che contiene il codice da eseguire in caso di errore. Il blocco catch accetta come parametro un’eccezione, che può essere usata per ottenere informazioni sull’errore. Ad esempio:

<?php
// Provo a eseguire un codice
try {
  // Apro un file
  $file = fopen('test.txt', 'r');

  // Leggo il contenuto del file
  $contenuto = fread($file, filesize('test.txt'));

  // Chiudo il file
  fclose($file);

  // Mostro il contenuto del file
  echo $contenuto;
}
// Catturo un'eccezione
catch (Exception $e) {
  // Mostro un messaggio di errore
  echo 'Si è verificato un errore: ' . $e->getMessage();
}
?>

Nell’esempio, se il file test.txt non esiste o non è leggibile, si verifica un errore che genera un’eccezione. L’eccezione viene catturata dal blocco catch, che mostra un messaggio di errore usando il metodo getMessage() dell’eccezione. In questo modo, si evita che l’errore blocchi l’esecuzione del codice, e si può gestire l’errore in maniera appropriata.

Per generare un’eccezione personalizzata, si può usare la parola chiave throw, seguita da un’istanza della classe Exception o di una sua sottoclasse. La classe Exception ha un costruttore che accetta due parametri: il messaggio dell’eccezione e il codice dell’eccezione. Ad esempio:

<?php
// Definisco una funzione che genera un'eccezione
function dividi($a, $b) {
  // Controllo se il divisore è zero
  if ($b == 0) {
    // Genero un'eccezione
    throw new Exception('Divisione per zero', 1);
  }
  // Restituisco il risultato della divisione
  return $a / $b;
}

// Provo a chiamare la funzione
try {
  // Chiamo la funzione con due numeri
  $risultato = dividi(10, 0);

  // Mostro il risultato
  echo $risultato;
}
// Catturo un'eccezione
catch (Exception $e) {
  // Mostro un messaggio di errore
  echo 'Si è verificato un errore: ' . $e->getMessage();
}
?>

Nell’esempio, se si chiama la funzione dividi() con il secondo parametro uguale a zero, si genera un’eccezione con il messaggio ‘Divisione per zero’ e il codice 1. L’eccezione viene catturata dal blocco catch, che mostra il messaggio di errore.

Per creare un'eccezione personalizzata, si può estendere la classe `Exception` e definire dei propri attributi e metodi. Ad esempio:


<?php
// Definisco una classe per le eccezioni di divisione per zero
class DivisionePerZeroException extends Exception {
  // Definisco un attributo per il divisore
  private $divisore;

  // Definisco un costruttore che accetta il divisore come parametro
  public function __construct($divisore) {
    // Invoco il costruttore della classe padre con un messaggio e un codice predefiniti
    parent::__construct('Divisione per zero', 1);

    // Assegno il valore del divisore all'attributo
    $this->divisore = $divisore;
  }

  // Definisco un metodo per ottenere il divisore
  public function getDivisore() {
    return $this->divisore;
  }
}

// Definisco una funzione che genera un'eccezione di divisione per zero
function dividi($a, $b) {
  // Controllo se il divisore è zero
  if ($b == 0) {
    // Genero un'eccezione di divisione per zero
    throw new DivisionePerZeroException($b);
  }
  // Restituisco il risultato della divisione
  return $a / $b;
}

// Provo a chiamare la funzione
try {
  // Chiamo la funzione con due numeri
  $risultato = dividi(10, 0);

  // Mostro il risultato
  echo $risultato;
}
// Catturo un'eccezione di divisione per zero
catch (DivisionePerZeroException $e) {
  // Mostro un messaggio di errore
  echo 'Si è verificato un errore: ' . $e->getMessage();

  // Mostro il divisore
  echo 'Divisore: ' . $e->getDivisore();
}
?>

Nell’esempio, si definisce una classe DivisionePerZeroException che estende la classe Exception e che ha un attributo divisore e un metodo getDivisore(). Si genera un’eccezione di questa classe nella funzione dividi() se il divisore è zero, e si cattura l’eccezione nel blocco catch, mostrando il messaggio e il divisore.

Per eseguire del codice indipendentemente dal risultato del blocco try-catch, si può usare il blocco finally, che viene eseguito dopo il blocco try o il blocco catch, a prescindere dal fatto che si sia verificata un’eccezione o meno. Il blocco finally è utile per rilasciare delle risorse o eseguire delle operazioni di pulizia. Ad esempio:

<?php
// Provo a eseguire un codice
try {
  // Apro un file
  $file = fopen('test.txt', 'r');

  // Leggo il contenuto del file
  $contenuto = fread($file, filesize('test.txt'));

  // Mostro il contenuto del file
  echo $contenuto;
}
// Catturo un'eccezione
catch (Exception $e) {
  // Mostro un messaggio di errore
  echo 'Si è verificato un errore: ' . $e->getMessage();
}
// Eseguo del codice in ogni caso
finally {
  // Chiudo il file se è aperto
  if (isset($file)) {
    fclose($file);
  }
}
?>

Nell’esempio, si usa il blocco finally per chiudere il file se è stato aperto, indipendentemente dal fatto che si sia verificato un errore o meno.

Conclusione

In conclusione, la gestione degli errori e delle eccezioni è un aspetto fondamentale dello sviluppo di applicazioni web in PHP. La segnalazione degli errori permette di comunicare la presenza di un errore nel codice, e di configurare il livello e il comportamento degli errori. Le eccezioni permettono di gestire gli errori in maniera più controllata e strutturata, tramite la struttura try-catch e la parola chiave throw. Per scegliere il meccanismo più adatto, bisogna valutare il tipo di errore, il livello di controllo e la qualità del codice.