json_decode mit JSON_THROW_ON_ERROR – Fehler, die man nicht übersehen kann
Kaputtes JSON gibt bei json_decode ein stilles null zurück – dasselbe null, das auch im gültigen JSON stehen kann. Ein Flag macht daraus eine Ausnahme, und aus der Fehlersuche wird eine Zeile Stacktrace.
Der Klassiker in jedem PHP-Projekt mit API-Anbindung:
$daten = json_decode($antwort, true);
$name = $daten['name'] ?? 'unbekannt';Sieht harmlos aus. Wenn $antwort aber eine HTML-Fehlerseite war, ein abgeschnittener Body oder schlicht leer, dann ist $daten jetzt null – und der Code läuft fröhlich weiter mit „unbekannt". Der Fehler zeigt sich Tage später in den Daten, nicht im Protokoll.
Erschwerend: json_decode('null') gibt ebenfalls null zurück, und das ist gültiges JSON. An null allein kann man also gar nicht erkennen, ob etwas schiefging.
Das Flag, das alles ändert
try {
$daten = json_decode($antwort, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new RuntimeException('Antwort war kein gültiges JSON: ' . $e->getMessage(), 0, $e);
}Ab PHP 7.3 gibt es JSON_THROW_ON_ERROR. Statt still null zu liefern, wirft json_decode eine JsonException mit einer klaren Meldung („Syntax error", „Control character error", „Maximum stack depth exceeded").
Auch beim Schreiben
// Wirft, wenn etwas nicht kodierbar ist (z. B. ungültiges UTF-8 oder eine Ressource)
$json = json_encode($nutzlast, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);JSON_UNESCAPED_SLASHES und JSON_UNESCAPED_UNICODE sind der Lesbarkeit wegen zu empfehlen: Ohne sie werden aus / ein \/ und aus ä ein ä.
Ein Helfer, den man einmal schreibt
declare(strict_types=1);
function json_lesen(string $roh): array
{
$wert = json_decode($roh, true, 512, JSON_THROW_ON_ERROR);
if (!is_array($wert)) {
throw new JsonException('Erwartet wurde ein JSON-Objekt, bekommen: ' . get_debug_type($wert));
}
return $wert;
}Zwei Zusicherungen in einer Funktion: Es ist gültiges JSON, und es ist eine Struktur, mit der der Aufrufer rechnen kann.
Fallstrick
Drei Dinge. Erstens: Das Flag hebelt json_last_error() für diesen Aufruf aus – prüf nicht beides, entscheide dich für die Ausnahme. Zweitens: Große Zahlen. JSON-IDs jenseits von PHP_INT_MAX werden zu float und verlieren Stellen; mit JSON_BIGINT_AS_STRING bleiben sie als String erhalten. Drittens: Die Tiefenbegrenzung von 512 ist kein Zierrat – tief verschachtelte Fremddaten sind ein bekannter Angriffsweg, lass den Wert lieber klein.
Saubere API-Anbindungen mit verständlichen Fehlern sind Teil meiner Arbeit – melde dich über bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Beträge und Zahlen in PHP formatieren – number_format, sprintf und Intl
1234.5 ist keine Anzeige, sondern ein Wert. Auf der Rechnung soll 1.234,50 € stehen, in der API 1234.50 und im Dateinamen 1234-50. Drei Aufgaben, drei Werkzeuge – und ein Fehler, den fast jeder einmal macht.
Benannte Argumente in PHP 8 – Schluss mit true, false, null, true
Ein Aufruf wie erstelle($a, true, false, null, true) sagt nichts darüber, was die Wahrheitswerte bedeuten. Mit benannten Argumenten steht es im Aufruf – und optionale Parameter lassen sich überspringen.
Reguläre Ausdrücke in PHP – benannte Gruppen statt $m[3]
Ein Treffer-Array aus Zahlen liest sich nach zwei Wochen wie eine Geheimschrift. Benannte Gruppen geben jedem Teil einen Namen – und preg_replace_callback ersetzt damit Dinge, die kein einfacher Ersetzungsstring kann.