# Fouten en exceptions in PHP

> Fouten en exceptions in PHP: Throwable, Error en Exception, try/catch/finally, globale handlers en veilige instellingen voor foutweergave en logbestanden.

Bron: https://phpsos.de/nl/php/fehler-und-exceptions/  
Stand: 25-10-2026  
Aanbieder: PHP SOS, PHP-noodhulp en serverbeveiliging. Directe hulp via WhatsApp: https://wa.me/491736494914?text=Hallo%20PHP%20SOS%2C%20wij%20hebben%20hulp%20nodig%20met%20onze%20PHP-server.%20Bedrijf%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kort gezegd:** PHP meldt problemen op twee manieren: als klassieke fouten zoals waarschuwingen en opmerkingen, die via `error_reporting` worden gestuurd, en als exceptions, die met `try` en `catch` kunnen worden afgevangen. Sinds PHP 7 werpen ook veel interne fouten een object van de klasse `Error`; samen met `Exception` implementeert dat de interface `Throwable`. In productie geldt: fouten vastleggen, nooit in de browser tonen. Op PHP 8.5 hoort vanwege PHP2Shell bovendien `fatal_error_backtraces=0` bij de overgangsmaatregelen.

## Twee werelden: klassieke fouten en exceptions

PHP stamt uit een tijd waarin fouten vooral als melding werden weergegeven: opmerkingen (`E_NOTICE`), waarschuwingen (`E_WARNING`), verouderde functies (`E_DEPRECATED`) en fatale fouten (`E_ERROR`). Veel van deze meldingen laten het script doorlopen, vaak met onjuiste of lege gegevens.

Exceptions werken anders. Ze onderbreken het normale verloop en springen naar het eerstvolgende passende `catch`-blok. Wordt er geen gevonden, dan eindigt het script. Voor beslissers is het verschil belangrijk: een stille waarschuwing kan ertoe leiden dat een bestelling onvolledig wordt opgeslagen zonder dat iemand het merkt. Een exception maakt het probleem zichtbaar en afhandelbaar.

Een onderschat voordeel van de klassieke meldingen zijn aanwijzingen van het type `E_DEPRECATED`. Ze kondigen aan dat een taalmiddel in een toekomstige PHP-versie vervalt. Wie ze in het log verzamelt en regelmatig beoordeelt, weet vóór een upgrade welke plaatsen moeten worden aangepast, en hoeft bij een dringend beveiligingslek niet eerst lang te testen.

## De Throwable-hiërarchie

Alles wat met `throw` kan worden geworpen en met `catch` kan worden gevangen, implementeert `Throwable`. Daaronder zijn er twee takken:

| Klasse | Doel | Voorbeelden van subklassen |
|---|---|---|
| `Exception` | verwachte fouten van de toepassing en van extensies | `ErrorException`, `PDOException`, eigen klassen |
| `Error` | interne fouten van PHP | `TypeError`, `ValueError`, `ArgumentCountError`, `ArithmeticError`, `DivisionByZeroError`, `UnhandledMatchError` |

Eigen foutklassen erven van `Exception`, niet van `Error`. Sinds PHP 8.0 werpen de meeste interne functies bij ongeldige parameters een `TypeError` of `ValueError`, in plaats van alleen een waarschuwing te geven. `strlen([])` is zo'n geval.

## try, catch en finally in de praktijk

```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) {
        // sinds PHP 8.0 is de variabele in de catch optioneel
        $log->error('Zahlungsdienst nicht erreichbar', ['bestellung' => $b->id()]);
        return false;
    } finally {
        $dienst->verbindungSchliessen();
    }
}
```

Meerdere klassen kunnen met `|` in één `catch` worden samengevoegd. Het `finally`-blok wordt altijd uitgevoerd, of er nu een fout is opgetreden of niet. Sinds PHP 8.0 is `throw` bovendien een expressie en kan het bijvoorbeeld achter `??` staan: `$id = $_GET['id'] ?? throw new InvalidArgumentException('id fehlt');`.

## Globale handlers: set_error_handler en set_exception_handler

Twee functies vangen af wat anders zou doorglippen. `set_exception_handler()` registreert een functie voor niet-afgevangen Throwables. Volgens de handleiding eindigt het script nadat de functie is aangeroepen; ze is dus geschikt voor het vastleggen in het log en een neutrale foutpagina, niet om door te werken.

Een handler die de volledige fout met tijdstip en een willekeurige code in het log schrijft en de bezoeker alleen een neutrale pagina met die code toont, heeft zich bewezen. De support kan het geval dan in het log terugvinden zonder dat interne details naar buiten lekken.

`set_error_handler()` vangt klassieke fouten af. De handleiding laat zien hoe u ze omzet in een `ErrorException`, zodat waarschuwingen als exceptions worden behandeld:

```php
<?php
set_error_handler(function (int $nr, string $text, string $datei, int $zeile): bool {
    if (!(error_reporting() & $nr)) {
        return false; // uitgesloten door error_reporting
    }
    if ($nr === E_DEPRECATED || $nr === E_USER_DEPRECATED) {
        return false; // aanwijzingen over verouderde code niet laten escaleren
    }
    throw new ErrorException($text, 0, $nr, $datei, $zeile);
});
```

Fatale fouten zoals een geheugenoverschrijding kunnen op deze manier niet worden afgevangen. Wat er bij een overschrijding van binnen gebeurt, legt de pagina [memory_limit en out-of-memory](https://phpsos.de/nl/php/out-of-memory/) uit.

## Foutweergave en logging configureren

De belangrijkste instellingen met hun standaardwaarden volgens de handleiding:

| Instelling | Standaard | Aanbeveling productie |
|---|---|---|
| `error_reporting` | `E_ALL` sinds PHP 8.0.0 | `E_ALL` |
| `display_errors` | `1` | `Off` |
| `display_startup_errors` | `1` sinds PHP 8.0.0 | `Off` |
| `log_errors` | `0` | `On` |
| `error_log` | leeg (log van de webserver of de SAPI) | eigen bestand buiten de webroot |
| `fatal_error_backtraces` | `1`, nieuw in PHP 8.5.0 | tijdelijk `0` (PHP2Shell) |

Sinds PHP 8.2.0 bepaalt `error_log_mode` de bestandsrechten van het logbestand, standaard `0644`. Bevatten de logs persoonsgegevens of paden, dan is een strengere waarde zinvol, zodat andere gebruikers op de server ze niet kunnen lezen. Met `ignore_repeated_errors` kunnen identieke meldingen uit hetzelfde bestand en dezelfde regel worden samengevoegd, zodat een foutlus het log niet overspoelt.

De meegeleverde `php.ini-production` zet `display_errors` al op `Off`. Volgens de handleiding werkt `ini_set('display_errors', ...)` tijdens de uitvoering niet op fatale fouten, en syntaxfouten treden op voordat een `ini_set()` uberhaupt draait. Deze waarden horen daarom in de serverconfiguratie. Achtergronden staan in het artikel [Foutweergave in productie uitschakelen](https://phpsos.de/nl/blog/display-errors-produktion/); hoe u logs zonder datalek bijhoudt, in het artikel [Veilig loggen](https://phpsos.de/nl/blog/sicher-loggen-php/).

## Foutafhandeling en PHP2Shell

Voor PHP 8.5 noemt php.net als een van de overgangsmaatregelen tegen PHP2Shell het instellen van `fatal_error_backtraces=0` en daarna PHP opnieuw starten. De overige maatregelen betreffen `memory_limit`, `post_max_size` en `session.upload_progress.enabled`. Geen daarvan vervangt de update naar PHP 8.5.12, 8.4.27, 8.3.36 of 8.2.35.

```ini
; alleen PHP 8.5, in php.ini of FPM-pool, daarna alle workers opnieuw starten
fatal_error_backtraces = 0
```

Foutlogs zijn na PHP2Shell bovendien een belangrijk bewijsmiddel. Nemen vanaf 20 oktober 2026 geheugenfouten of afgebroken workers toe, dan kan dat wijzen op aanvalspogingen, maar het kan ook onschuldige oorzaken hebben. Bewaar de logs en beoordeel ze samen met de toegangslogs, zoals beschreven in de gids [Weblogs na een aanval analyseren](https://phpsos.de/nl/ratgeber/logfiles-auswerten/).

## Hoe helpt PHP SOS concreet?

- Wij controleren de werkzame instellingen voor foutweergave en logging per website en stellen ze productieklaar in.
- Wij voeren de PHP2Shell-overgangsmaatregelen door die passen bij de PHP-versie en starten alle workers opnieuw.
- Wij beveiligen fout- en toegangslogs vanaf 20 oktober 2026 en beoordelen ze op bijzonderheden.
- In het kader van de [security-monitoring](https://phpsos.de/nl/leistungen/security-monitoring/) melden wij ongebruikelijke foutopeenhopingen, in plaats van ze in het log te laten wegzakken.


## Veelgestelde vragen

**Wat is het verschil tussen Error en Exception?**  
Beide implementeren de interface Throwable. Exception is bedoeld voor fouten die een toepassing verwacht en afhandelt, zoals een mislukte databaseverbinding. Error staat voor interne fouten van PHP, zoals een TypeError of een deling door nul.

**Moet display_errors in productie aanstaan?**  
Nee. Foutmeldingen in de browser verraden paden, queries en soms toegangsgegevens. In productie hoort display_errors op Off en log_errors op On, zodat fouten in het log terechtkomen in plaats van bij de bezoeker.

**Kan een geheugenoverschrijding met try/catch worden afgevangen?**  
Nee. Overschrijdt een script memory_limit, dan beëindigt PHP het met een fatale fout die niet als exception kan worden afgevangen. Ze verschijnt alleen in het foutenlog, mits log_errors actief is.

**Wat is fatal_error_backtraces?**  
Een instelling die er sinds PHP 8.5.0 is en die fatale fouten van een backtrace voorziet. Ze is standaard actief. Als overgangsmaatregel tegen PHP2Shell noemt php.net voor PHP 8.5 het op 0 zetten ervan en daarna PHP opnieuw starten.

## Bronnen

- [PHP-handleiding: configuratie van de foutafhandeling](https://www.php.net/manual/de/errorfunc.configuration.php)
- [PHP-handleiding: klasse Error](https://www.php.net/manual/de/class.error.php)
- [PHP-handleiding: ErrorException](https://www.php.net/manual/en/class.errorexception.php)
- [PHP-handleiding: set_exception_handler](https://www.php.net/manual/en/function.set-exception-handler.php)
- [php.net: beveiligingsmeldingen](https://www.php.net/)
