Ce face try / catch / finally / throw
Când ceva nu merge (fișierul lipsește, baza de date nu răspunde, datele sunt greșite), codul poate arunca o excepție cu throw. Excepția oprește execuția normală și urcă până la primul bloc catch potrivit. Dacă nu o prinde nimeni, scriptul se oprește cu Fatal error: Uncaught ....
Pui codul riscant în try. Fiecare catch prinde un tip de excepție (și tipurile care îl extind). Poți prinde mai multe tipuri în același bloc cu |: catch (TypeError | ValueError $e). Blocul finally rulează mereu, cu sau fără eroare, de exemplu pentru a închide un fișier.
În PHP 8, aproape toate erorile grave ale limbajului (tip greșit, împărțire la zero cu intdiv, metodă inexistentă) sunt și ele aruncate, ca obiecte Error. catch (Throwable $e) prinde absolut tot: și Exception, și Error.
Exemple
Exemplul 1: Aruncare și prindere
<?php
function imparte(float $a, float $b): float
{
if ($b == 0) {
throw new InvalidArgumentException("Nu se poate împărți la zero.");
}
return $a / $b;
}
try {
echo imparte(10, 4) . "\n";
echo imparte(5, 0) . "\n";
echo "Această linie nu mai rulează.\n";
} catch (InvalidArgumentException $e) {
echo "Eroare: " . $e->getMessage() . "\n";
}
echo "Scriptul continuă.";
Rezultat
2.5
Eroare: Nu se poate împărți la zero.
Scriptul continuă.
Exemplul 2: Mai multe blocuri catch și finally
PHP alege primul catch care se potrivește. finally rulează în ambele cazuri.
<?php
function proceseaza(mixed $cantitate): void
{
try {
echo "Procesez " . var_export($cantitate, true) . ": ";
echo intdiv(100, $cantitate) . " lei/buc\n";
} catch (DivisionByZeroError $e) {
echo "cantitatea nu poate fi 0\n";
} catch (TypeError $e) {
echo "cantitatea trebuie să fie număr întreg\n";
} finally {
echo " (verificare terminată)\n";
}
}
proceseaza(4);
proceseaza(0);
proceseaza("multe");
Rezultat
Procesez 4: 25 lei/buc
(verificare terminată)
Procesez 0: cantitatea nu poate fi 0
(verificare terminată)
Procesez 'multe': cantitatea trebuie să fie număr întreg
(verificare terminată)
Exemplul 3: throw ca expresie (PHP 8+)
<?php
$config = ["db_host" => "localhost"];
try {
$host = $config["db_host"] ?? throw new RuntimeException("Lipsește db_host");
echo "Host: $host\n";
$nume = $config["db_name"] ?? throw new RuntimeException("Lipsește db_name");
} catch (RuntimeException $e) {
echo $e->getMessage();
}
Rezultat
Host: localhost
Lipsește db_name
Greșeli frecvente
- Prinzi excepția și nu faci nimic cu ea:
catch (Exception $e) {}. Eroarea dispare fără urmă și problema devine foarte greu de găsit. Măcar scrie-o în jurnal cuerror_log. - Prinzi
Exceptionși te aștepți să prinzi și unTypeError. Erorile limbajului extindError, nuException. FoloseșteThrowabledacă vrei să prinzi tot. - Pui un
catchgeneral înaintea unuia specific. Primul care se potrivește câștigă, deci cel specific nu mai rulează niciodată.
Comenzi înrudite
Exception: Clasa de bază pentru excepții. Extinde-o ca să creezi tipuri proprii de erori pentru aplicația ta.set_exception_handler: Setează funcția care rulează când o excepție nu este prinsă de niciun bloc catch.error_log: Scrie un mesaj în jurnalul de erori al serverului sau într-un fișier ales de tine.set_error_handler: Înlocuiește tratarea standard a avertismentelor și notificărilor PHP cu o funcție scrisă de tine.