# Erori și excepții în PHP

> Erori și excepții în PHP: Throwable, Error și Exception, try/catch/finally, handlere globale și setări sigure pentru afișarea erorilor și pentru loguri.

Sursa: https://phpsos.de/ro/php/fehler-und-exceptions/  
Stadiu: 25.10.2026  
Furnizor: PHP SOS, Asistență de urgență PHP și securitatea serverelor. Ajutor imediat pe WhatsApp: https://wa.me/491736494914?text=Bun%C4%83%20ziua%2C%20PHP%20SOS%2C%20avem%20nevoie%20de%20ajutor%20cu%20serverul%20nostru%20PHP.%20Firma%3A%20%E2%80%A6%20Site%3A%20%E2%80%A6

**Pe scurt:** PHP raportează problemele pe două căi: ca erori clasice, precum avertismente și notificări, controlate prin `error_reporting`, și ca excepții, care pot fi prinse cu `try` și `catch`. Din PHP 7, multe erori interne aruncă și ele un obiect al clasei `Error`; împreună cu `Exception`, aceasta implementează interfața `Throwable`. În producție se aplică regula: erorile se înregistrează în log, nu se afișează niciodată în browser. Pe PHP 8.5, din cauza PHP2Shell, `fatal_error_backtraces=0` face parte în plus dintre măsurile de tranziție.

## Două lumi: erori clasice și excepții

PHP provine dintr-o vreme în care erorile erau afișate mai ales ca mesaje: notificări (`E_NOTICE`), avertismente (`E_WARNING`), funcții depășite (`E_DEPRECATED`) și erori fatale (`E_ERROR`). Multe dintre aceste mesaje lasă scriptul să ruleze mai departe, adesea cu date greșite sau goale.

Excepțiile funcționează altfel. Ele întrerup desfășurarea normală și sar la următorul bloc `catch` potrivit. Dacă nu se găsește niciunul, scriptul se încheie. Pentru factorii de decizie, diferența este importantă: un avertisment tăcut poate duce la salvarea incompletă a unei comenzi, fără ca cineva să observe. O excepție face problema vizibilă și tratabilă.

Un beneficiu subestimat al mesajelor clasice sunt notificările de tip `E_DEPRECATED`. Ele anunță că un mijloc al limbajului dispare într-o versiune PHP viitoare. Cine le colectează în log și le evaluează regulat știe înainte de un upgrade ce locuri trebuie adaptate și nu trebuie să testeze îndelung abia în cazul unei vulnerabilități urgente.

## Ierarhia Throwable

Tot ce poate fi aruncat cu `throw` și prins cu `catch` implementează `Throwable`. Dedesubt există două ramuri:

| Clasă | Scop | Exemple de subclase |
|---|---|---|
| `Exception` | erori previzibile ale aplicației și ale extensiilor | `ErrorException`, `PDOException`, clase proprii |
| `Error` | erori interne ale PHP | `TypeError`, `ValueError`, `ArgumentCountError`, `ArithmeticError`, `DivisionByZeroError`, `UnhandledMatchError` |

Clasele proprii de eroare derivă din `Exception`, nu din `Error`. Din PHP 8.0, majoritatea funcțiilor interne aruncă la parametri invalizi un `TypeError` sau `ValueError`, în loc să emită doar un avertisment. `strlen([])` este un astfel de caz.

## try, catch și finally în practică

```php
<?php
declare(strict_types=1);

final class ZahlungFehlgeschlagen extends RuntimeException {}

function bezahlen(Bestellung $b, Zahlungsdienst $dienst, LoggerInterface $log): bool
{
    try {
        $dienst->belasten($b->betrag(), $b->referenz());
        return true;
    } catch (ZahlungFehlgeschlagen $e) {
        $log->warning('Zahlung abgelehnt', ['bestellung' => $b->id(), 'exception' => $e]);
        return false;
    } catch (TimeoutException | VerbindungsFehler) {
        // din PHP 8.0 variabila din catch este opțională
        $log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
        return false;
    } finally {
        $dienst->verbindungSchliessen();
    }
}
```

Mai multe clase pot fi grupate într-un singur `catch` cu `|`. Blocul `finally` rulează întotdeauna, indiferent dacă a apărut o eroare sau nu. Din PHP 8.0, `throw` este în plus o expresie și poate sta, de exemplu, după `??`: `$id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');`.

## Handlere globale: set_error_handler și set_exception_handler

Două funcții interceptează ceea ce altfel ar trece nebăgat în seamă. `set_exception_handler()` înregistrează o funcție pentru Throwable-urile neprinse. Potrivit manualului, scriptul se încheie după apelarea ei; este deci potrivită pentru înregistrare în log și o pagină de eroare neutră, nu pentru a continua munca.

S-a dovedit eficient un handler care scrie eroarea completă în log, cu momentul și un identificator aleatoriu, și arată vizitatorului doar o pagină neutră cu acest identificator. Suportul poate regăsi apoi cazul în log, fără ca detalii interne să ajungă în exterior.

`set_error_handler()` interceptează erorile clasice. Manualul arată cum pot fi transformate într-o `ErrorException`, astfel încât avertismentele să fie tratate ca excepții:

```php
<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
    if (!(error_reporting() & $nr)) {
        return false; // exclus de error_reporting
    }
    if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
        return false; // nu escalada notificările despre elemente depășite
    }
    throw new ErrorException($text, 0, $nr, $datei, $zeile);
});
```

Erorile fatale, precum o depășire de memorie, nu pot fi interceptate pe această cale. Ce se întâmplă în interior la o depășire explică pagina [memory_limit și Out-of-Memory](https://phpsos.de/ro/php/out-of-memory/).

## Configurarea afișării erorilor și a înregistrării în log

Cele mai importante setări, cu valorile lor implicite potrivit manualului:

| Setare | Implicit | Recomandare pentru producție |
|---|---|---|
| `error_reporting` | `E_ALL` din PHP 8.0.0 | `E_ALL` |
| `display_errors` | `1` | `Off` |
| `display_startup_errors` | `1` din PHP 8.0.0 | `Off` |
| `log_errors` | `0` | `On` |
| `error_log` | gol (logul serverului web, respectiv al SAPI) | fișier propriu, în afara webroot-ului |
| `fatal_error_backtraces` | `1`, nou în PHP 8.5.0 | temporar `0` (PHP2Shell) |

Din PHP 8.2.0, `error_log_mode` stabilește drepturile fișierului de log, implicit `0644`. Dacă logurile conțin date personale sau căi, o valoare mai strictă este potrivită, ca alți utilizatori de pe server să nu le poată citi. Cu `ignore_repeated_errors` pot fi grupate mesajele identice din același fișier și de pe aceeași linie, pentru ca o buclă de erori să nu inunde logul.

Fișierul `php.ini-production` livrat setează deja `display_errors` pe `Off`. Potrivit manualului, `ini_set('display_errors', ...)` nu are efect la execuție asupra erorilor fatale, iar erorile de sintaxă apar înainte ca vreun `ini_set()` să ruleze. Aceste valori aparțin de aceea configurației serverului. Contextul se găsește în articolul [Dezactivarea afișării erorilor în producție](https://phpsos.de/ro/blog/display-errors-produktion/); cum se țin logurile fără scurgeri de date, în articolul [Logare sigură](https://phpsos.de/ro/blog/sicher-loggen-php/).

## Tratarea erorilor și PHP2Shell

Pentru PHP 8.5, php.net indică drept una dintre măsurile de tranziție împotriva PHP2Shell setarea `fatal_error_backtraces=0` și repornirea ulterioară a PHP. Celelalte măsuri privesc `memory_limit`, `post_max_size` și `session.upload_progress.enabled`. Niciuna dintre ele nu înlocuiește actualizarea la PHP 8.5.12, 8.4.27, 8.3.36 sau 8.2.35.

```ini
; doar PHP 8.5, în php.ini sau în pool-ul FPM, apoi repornește toți workerii
fatal_error_backtraces = 0
```

Logurile de erori sunt, după PHP2Shell, și un important mijloc de probă. Dacă începând cu 20.10.2026 se înmulțesc erorile de memorie sau workerii întrerupți, aceasta poate indica tentative de atac, dar poate avea și cauze inofensive. Păstrați logurile și evaluați-le împreună cu logurile de acces, așa cum este descris în ghidul [Analiza logurilor serverului web după un atac](https://phpsos.de/ro/ratgeber/logfiles-auswerten/).

## Cum ajută PHP SOS concret?

- Verificăm setările efective pentru afișarea erorilor și înregistrarea în log, pentru fiecare site, și le configurăm potrivit pentru producție.
- Aplicăm măsurile de tranziție PHP2Shell potrivite versiunii PHP și repornim toți workerii.
- Securizăm logurile de erori și de acces începând cu 20.10.2026 și le analizăm pentru neregularități.
- În cadrul [monitorizării de securitate](https://phpsos.de/ro/leistungen/security-monitoring/) raportăm acumulările neobișnuite de erori, în loc să le lăsăm să se piardă în log.


## Întrebări frecvente

**Care este diferența dintre Error și Exception?**  
Ambele implementează interfața Throwable. Exception este gândită pentru erori pe care o aplicație le așteaptă și le tratează, de exemplu o conexiune eșuată la baza de date. Error reprezintă erori interne ale PHP, precum un TypeError sau o împărțire la zero.

**Ar trebui display_errors să fie activat în producție?**  
Nu. Mesajele de eroare din browser dezvăluie căi, interogări și uneori date de acces. În producție, display_errors trebuie să fie Off și log_errors On, astfel încât erorile să ajungă în log, nu la vizitator.

**Poate fi interceptată o depășire de memorie cu try/catch?**  
Nu. Dacă un script depășește memory_limit, PHP îl încheie cu o eroare fatală care nu poate fi prinsă ca excepție. Ea apare doar în logul de erori, dacă log_errors este activ.

**Ce este fatal_error_backtraces?**  
O setare existentă din PHP 8.5.0, care adaugă un backtrace la erorile fatale. Este activă implicit. Ca măsură de tranziție împotriva PHP2Shell, php.net indică pentru PHP 8.5 setarea ei la 0 și repornirea ulterioară a PHP.

## Surse

- [Manualul PHP: configurarea gestionării erorilor](https://www.php.net/manual/de/errorfunc.configuration.php)
- [Manualul PHP: clasa Error](https://www.php.net/manual/de/class.error.php)
- [Manualul PHP: ErrorException](https://www.php.net/manual/en/class.errorexception.php)
- [Manualul PHP: set_exception_handler](https://www.php.net/manual/en/function.set-exception-handler.php)
- [php.net: anunțuri de securitate](https://www.php.net/)
