# Pogreške i iznimke (exceptions) u PHP-u

> Pogreške i iznimke u PHP-u: Throwable, Error i Exception, try/catch/finally, globalni handleri i sigurne postavke za ispis pogrešaka i zapisnike.

Izvor: https://phpsos.de/hr/php/fehler-und-exceptions/  
Stanje: 25.10.2026  
Pružatelj: PHP SOS, PHP hitna pomoć i sigurnost poslužitelja. Hitna pomoć putem WhatsAppa: https://wa.me/491736494914?text=Pozdrav%20PHP%20SOS%2C%20trebamo%20pomo%C4%87%20s%20na%C5%A1im%20PHP%20poslu%C5%BEiteljem.%20Tvrtka%3A%20%E2%80%A6%20Web-stranica%3A%20%E2%80%A6

**Ukratko:** PHP prijavljuje probleme na dva načina: kao klasične pogreške poput upozorenja i napomena, kojima se upravlja putem `error_reporting`, te kao iznimke koje se mogu uhvatiti s `try` i `catch`. Od PHP-a 7 i mnoge interne pogreške bacaju objekt klase `Error`; zajedno s `Exception` implementira sučelje `Throwable`. U produkciji vrijedi: pogreške zapisivati, nikad ih ne prikazivati u pregledniku. Na PHP-u 8.5 zbog PHP2Shella među prijelazne mjere spada i `fatal_error_backtraces=0`.

## Dva svijeta: klasične pogreške i iznimke

PHP potječe iz vremena u kojem su se pogreške ponajprije ispisivale kao poruke: napomene (`E_NOTICE`), upozorenja (`E_WARNING`), zastarjele funkcije (`E_DEPRECATED`) i fatalne pogreške (`E_ERROR`). Mnoge od tih poruka dopuštaju da skripta nastavi raditi, često s pogrešnim ili praznim podacima.

Iznimke rade drukčije. Prekidaju uobičajeni tijek i skaču na sljedeći odgovarajući `catch` blok. Ako ga nema, skripta završava. Za donositelje odluka razlika je važna: tiho upozorenje može dovesti do toga da se narudžba spremi nepotpuno, a da to nitko ne primijeti. Iznimka problem čini vidljivim i obradivim.

Podcijenjena korist klasičnih poruka su napomene tipa `E_DEPRECATED`. One najavljuju da će jezično sredstvo otpasti u budućoj verziji PHP-a. Tko ih skuplja u zapisniku i redovito analizira, prije nadogradnje zna koja mjesta treba prilagoditi i kod hitne sigurnosne ranjivosti ne mora dugo testirati.

## Hijerarhija Throwable

Sve što se može baciti s `throw` i uhvatiti s `catch` implementira `Throwable`. Ispod njega postoje dvije grane:

| Klasa | Svrha | Primjeri potklasa |
|---|---|---|
| `Exception` | pogreške koje se mogu očekivati u aplikaciji i ekstenzijama | `ErrorException`, `PDOException`, vlastite klase |
| `Error` | interne pogreške PHP-a | `TypeError`, `ValueError`, `ArgumentCountError`, `ArithmeticError`, `DivisionByZeroError`, `UnhandledMatchError` |

Vlastite klase pogrešaka nasljeđuju `Exception`, a ne `Error`. Od PHP-a 8.0 većina internih funkcija pri nevaljanim parametrima baca `TypeError` ili `ValueError`, umjesto da samo ispiše upozorenje. `strlen([])` je jedan takav slučaj.

## try, catch i finally u praksi

```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) {
        // od PHP-a 8.0 varijabla u catchu nije obavezna
        $log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
        return false;
    } finally {
        $dienst->verbindungSchliessen();
    }
}
```

Više se klasa može objediniti znakom `|` u jednom `catchu`. Blok `finally` izvršava se uvijek, bez obzira je li došlo do pogreške. Od PHP-a 8.0 `throw` je uz to izraz i može stajati, primjerice, iza `??`: `$id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');`.

## Globalni handleri: set_error_handler i set_exception_handler

Dvije funkcije hvataju ono što bi inače promaknulo. `set_exception_handler()` registrira funkciju za neuhvaćene Throwable objekte. Prema priručniku skripta završava nakon što se ona pozove; pogodna je dakle za zapisivanje i neutralnu stranicu s pogreškom, a ne za nastavak rada.

Dobro se pokazao handler koji potpunu pogrešku s vremenom i slučajnom oznakom upisuje u zapisnik, a posjetitelju prikazuje samo neutralnu stranicu s tom oznakom. Podrška tada slučaj može pronaći u zapisniku, a da interni detalji ne procure prema van.

`set_error_handler()` hvata klasične pogreške. Priručnik pokazuje kako ih pretvoriti u `ErrorException` kako bi se upozorenja obrađivala kao iznimke:

```php
<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
    if (!(error_reporting() & $nr)) {
        return false; // isključeno putem error_reporting
    }
    if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
        return false; // napomene o zastarjelom ne eskalirati
    }
    throw new ErrorException($text, 0, $nr, $datei, $zeile);
});
```

Fatalne pogreške poput prekoračenja memorije ovim se putem ne mogu uhvatiti. Što se pri prekoračenju događa iznutra, objašnjava stranica [memory_limit i Out-of-Memory](https://phpsos.de/hr/php/out-of-memory/).

## Konfiguriranje ispisa pogrešaka i zapisivanja

Najvažnije postavke sa zadanim vrijednostima prema priručniku:

| Postavka | Zadano | Preporuka za produkciju |
|---|---|---|
| `error_reporting` | `E_ALL` od PHP-a 8.0.0 | `E_ALL` |
| `display_errors` | `1` | `Off` |
| `display_startup_errors` | `1` od PHP-a 8.0.0 | `Off` |
| `log_errors` | `0` | `On` |
| `error_log` | prazno (zapisnik web-poslužitelja odnosno SAPI-ja) | vlastita datoteka izvan webrootea |
| `fatal_error_backtraces` | `1`, novo u PHP-u 8.5.0 | privremeno `0` (PHP2Shell) |

Od PHP-a 8.2.0 `error_log_mode` određuje prava datoteke zapisnika, prema zadanim postavkama `0644`. Ako zapisnici sadrže osobne podatke ili putanje, smislena je stroža vrijednost kako ih drugi korisnici na poslužitelju ne bi mogli čitati. S `ignore_repeated_errors` mogu se sažeti identične poruke iz iste datoteke i retka, kako petlja pogrešaka ne bi preplavila zapisnik.

Isporučeni `php.ini-production` već postavlja `display_errors` na `Off`. Prema priručniku `ini_set('display_errors', ...)` tijekom izvođenja ne djeluje na fatalne pogreške, a sintaksne pogreške nastaju prije nego što se `ini_set()` uopće izvrši. Te vrijednosti zato pripadaju u konfiguraciju poslužitelja. Pozadinu donosi članak [Isključivanje ispisa pogrešaka u produkciji](https://phpsos.de/hr/blog/display-errors-produktion/); kako voditi zapisnike bez curenja podataka, opisuje članak [Sigurno zapisivanje](https://phpsos.de/hr/blog/sicher-loggen-php/).

## Obrada pogrešaka i PHP2Shell

Za PHP 8.5 php.net kao jednu od prijelaznih mjera protiv PHP2Shella navodi postavljanje `fatal_error_backtraces=0` i potom ponovno pokretanje PHP-a. Ostale mjere tiču se `memory_limit`, `post_max_size` i `session.upload_progress.enabled`. Nijedna od njih ne zamjenjuje ažuriranje na PHP 8.5.12, 8.4.27, 8.3.36 ili 8.2.35.

```ini
; samo PHP 8.5, u php.ini ili FPM poolu, zatim ponovno pokrenuti sve workere
fatal_error_backtraces = 0
```

Zapisnici pogrešaka nakon PHP2Shella uz to su važan dokaz. Ako se od 20. 10. 2026. nagomilaju pogreške memorije ili prekinuti workeri, to može upućivati na pokušaje napada, ali može imati i bezazlene uzroke. Sačuvajte zapisnike i analizirajte ih zajedno sa zapisnicima pristupa, kako je opisano u vodiču [Analiza zapisnika web-poslužitelja nakon napada](https://phpsos.de/hr/ratgeber/logfiles-auswerten/).

## Kako PHP SOS konkretno pomaže?

- Provjeravamo djelotvorne postavke za ispis pogrešaka i zapisivanje po web-stranici i podešavamo ih za produkciju.
- Postavljamo prijelazne mjere PHP2Shella u skladu s verzijom PHP-a i ponovno pokrećemo sve workere.
- Osiguravamo zapisnike pogrešaka i pristupa od 20. 10. 2026. i analiziramo ih zbog neobičnosti.
- U okviru [sigurnosnog nadzora](https://phpsos.de/hr/leistungen/security-monitoring/) prijavljujemo neobična nagomilavanja pogrešaka, umjesto da ih pustimo da se izgube u zapisniku.


## Česta pitanja

**Koja je razlika između Error i Exception?**  
Oba implementiraju sučelje Throwable. Exception je namijenjen pogreškama koje aplikacija očekuje i obrađuje, primjerice neuspjelom spajanju na bazu podataka. Error označava interne pogreške PHP-a poput TypeErrora ili dijeljenja s nulom.

**Treba li display_errors u produkciji biti uključen?**  
Ne. Poruke o pogreškama u pregledniku otkrivaju putanje, upite, a ponekad i pristupne podatke. U produkciji display_errors treba biti Off, a log_errors On, kako bi pogreške završavale u zapisniku, a ne kod posjetitelja.

**Može li se prekoračenje memorije uhvatiti s try/catch?**  
Ne. Ako skripta prekorači memory_limit, PHP je prekida fatalnom pogreškom koja se ne može uhvatiti kao iznimka. Pojavljuje se samo u zapisniku pogrešaka, uz uvjet da je log_errors aktivan.

**Što je fatal_error_backtraces?**  
Postavka koja postoji od PHP-a 8.5.0 i fatalnim pogreškama dodaje backtrace. Prema zadanim je postavkama aktivna. Kao prijelaznu mjeru protiv PHP2Shella php.net za PHP 8.5 navodi da je treba postaviti na 0 i zatim ponovno pokrenuti PHP.

## Izvori

- [PHP priručnik: Konfiguracija obrade pogrešaka](https://www.php.net/manual/de/errorfunc.configuration.php)
- [PHP priručnik: Klasa Error](https://www.php.net/manual/de/class.error.php)
- [PHP priručnik: ErrorException](https://www.php.net/manual/en/class.errorexception.php)
- [PHP priručnik: set_exception_handler](https://www.php.net/manual/en/function.set-exception-handler.php)
- [php.net: Sigurnosne obavijesti](https://www.php.net/)
