W3docs

throw

In PHP, la parola chiave "throw" viene usata per generare un'eccezione e gestire errori e condizioni impreviste nel codice.

La parola chiave throw in PHP

La parola chiave throw interrompe l'esecuzione normale nel punto in cui viene chiamata e genera un'eccezione — un oggetto che segnala che qualcosa è andato storto. Il controllo salta immediatamente fuori dalla funzione corrente e risale lo stack delle chiamate finché non trova un blocco catch corrispondente. Se nessun catch corrisponde, PHP interrompe lo script con un errore fatale.

Questa pagina tratta la sintassi di throw, quando usarlo al posto della restituzione di un valore di errore, come lanciare eccezioni predefinite e personalizzate, il rilancio e il concatenamento, e la funzionalità di PHP 8 che permette di usare throw come espressione. Per un quadro più ampio, vedere Eccezioni in PHP e il flusso try/catch/finally.

Sintassi

throw new Exception("Error message here");

throw deve ricevere un valore che sia un'istanza di Throwable — in pratica un Exception (o una delle sue sottoclassi) oppure un Error. La stringa passata al costruttore diventa il messaggio dell'eccezione, che si legge in seguito con getMessage().

Poiché un'eccezione lanciata svolge lo stack, qualsiasi codice dopo throw nello stesso blocco non viene mai eseguito:

throw new Exception("stop here");
echo "this line is unreachable"; // never executes

Perché usare throw invece di restituire un errore?

Restituire un valore speciale (come false o -1) per segnalare un fallimento costringe ogni chiamante a ricordarsi di verificarlo, e il significato del valore è facile da perdere. throw rende il fallimento impossibile da ignorare: l'eccezione si propaga automaticamente finché qualcosa non la gestisce, e porta con sé un messaggio, un codice, uno stack trace e il file e la riga in cui è avvenuta.

Usare throw per condizioni eccezionali da cui la funzione corrente non può ragionevolmente riprendersi — argomenti non validi, una connessione al database fallita, un file obbligatorio mancante — e lasciare che un chiamante a un livello superiore decida cosa fare.

Un esempio di base

Qui una funzione divide() lancia un'eccezione quando le viene chiesto di dividere per zero, e il chiamante la intercetta:

<?php

function divide(int $numerator, int $denominator): float
{
    if ($denominator === 0) {
        throw new InvalidArgumentException("Cannot divide by zero.");
    }
    return $numerator / $denominator;
}

try {
    echo divide(10, 2), PHP_EOL; // 5
    echo divide(10, 0), PHP_EOL; // throws before printing
} catch (InvalidArgumentException $e) {
    echo "Caught: " . $e->getMessage() . PHP_EOL;
}

Output:

5
Caught: Cannot divide by zero.

La prima chiamata ha successo e stampa 5. La seconda chiamata lancia l'eccezione, quindi il suo echo non viene mai eseguito e il controllo salta direttamente al blocco catch.

Lanciare un'eccezione personalizzata

Estendere Exception permette di dare a ogni tipo di errore il proprio nome, così i chiamanti possono intercettare esattamente i fallimenti che gli interessano e ignorare il resto:

<?php

class InsufficientFundsException extends Exception {}

function withdraw(float $balance, float $amount): float
{
    if ($amount > $balance) {
        throw new InsufficientFundsException(
            "Cannot withdraw $amount; balance is only $balance."
        );
    }
    return $balance - $amount;
}

try {
    echo withdraw(100, 250), PHP_EOL;
} catch (InsufficientFundsException $e) {
    echo "Declined: " . $e->getMessage() . PHP_EOL;
}

Output:

Declined: Cannot withdraw 250; balance is only 100.

Vedere Classi di eccezione personalizzate per maggiori informazioni sull'estensione di Exception.

Messaggio, codice e eccezione precedente

Il costruttore di Exception accetta tre argomenti — message, code e un'eccezione previous. Il terzo permette di racchiudere un errore di basso livello in uno più significativo senza perdere la causa originale (questo si chiama concatenamento di eccezioni):

<?php

try {
    try {
        throw new RuntimeException("Disk read failed", 13);
    } catch (RuntimeException $low) {
        // Re-throw a higher-level exception, keeping the original as the cause.
        throw new Exception("Could not load config", 0, $low);
    }
} catch (Exception $e) {
    echo $e->getMessage() . PHP_EOL;                 // Could not load config
    echo "Caused by: " . $e->getPrevious()->getMessage() . PHP_EOL; // Disk read failed
    echo "Original code: " . $e->getPrevious()->getCode() . PHP_EOL; // 13
}

Output:

Could not load config
Caused by: Disk read failed
Original code: 13

Rilanciare in un blocco catch

Non è necessario gestire completamente un'eccezione dove la si intercetta. Un blocco catch può eseguire del lavoro (registrarla, aggiungere contesto) e poi lanciare di nuovo con throw per lasciare che un gestore esterno completi il lavoro:

<?php

function loadUser(int $id): array
{
    try {
        throw new RuntimeException("Database is down");
    } catch (RuntimeException $e) {
        error_log("loadUser($id) failed: " . $e->getMessage());
        throw $e; // pass it on
    }
}

try {
    loadUser(7);
} catch (RuntimeException $e) {
    echo "Handled at top level: " . $e->getMessage() . PHP_EOL;
}

Output:

Handled at top level: Database is down

throw come espressione (PHP 8+)

Da PHP 8.0, throw è un'espressione, non solo un'istruzione, quindi può essere usato in contesti che si aspettano un valore — come gli operatori ?: e ?? o una funzione freccia:

<?php

function getConfig(array $config, string $key): string
{
    // Throw inline when the key is missing.
    return $config[$key] ?? throw new InvalidArgumentException("Missing key: $key");
}

echo getConfig(['env' => 'prod'], 'env'), PHP_EOL; // prod

try {
    getConfig(['env' => 'prod'], 'region');
} catch (InvalidArgumentException $e) {
    echo $e->getMessage() . PHP_EOL;
}

Output:

prod
Missing key: region

Errori comuni

  • Lanciare senza un try/catch da nessuna parte nello stack. Un'eccezione non intercettata diventa un errore fatale e interrompe lo script. Intercettarla sempre da qualche parte, oppure registrare un fallback con set_exception_handler().
  • Lanciare una stringa o un array. throw richiede un oggetto che implementa Throwable; throw "oops"; è un errore di sintassi.
  • Silenziare le eccezioni. Un blocco catch vuoto nasconde i bug. Registrare almeno il messaggio, oppure rilanciare l'eccezione.
  • Usare le eccezioni per il normale flusso di controllo. Lanciare su ogni ramo previsto (ad esempio, "utente non trovato" durante una ricerca ordinaria) è lento e confuso — riservarle ai casi genuinamente eccezionali.
  • throw genera un Throwable e svolge immediatamente lo stack fino al catch corrispondente più vicino.
  • Preferirlo ai valori di ritorno magici in modo che i fallimenti non possano essere ignorati silenziosamente.
  • Estendere Exception per creare tipi di errore con nome; passare un'eccezione previous per concatenare le cause.
  • Intercettare, aggiungere contesto e lanciare di nuovo con throw per lasciare che un gestore esterno decida.
  • In PHP 8+, throw funziona come espressione all'interno di ??, ?: e funzioni freccia.

Continuare con il blocco try, il blocco catch e finally per vedere il ciclo completo di gestione delle eccezioni.

Pratica

Pratica
Cosa fa l'istruzione 'throw' in PHP?
Cosa fa l'istruzione 'throw' in PHP?
Was this page helpful?