MWCodebymw.de ↗
PHP

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

#PHP#JSON#Fehlerbehandlung#API#json_decode

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 →