json_decode()
debt(d5/e1/b3/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list phpstan and rector as the tools that catch the missing JSON_THROW_ON_ERROR or absent json_last_error() check. These are specialist static analysis tools, not default linters or the compiler, placing this squarely at d5.
Closest to 'one-line patch or single-call swap' (e1). The quick_fix is a direct one-line replacement: add JSON_THROW_ON_ERROR (and optionally true for assoc mode) to the existing json_decode call. No structural refactor is required.
Closest to 'localised tax' (b3). The issue is call-site specific — each json_decode() call must be updated individually, but the fix is contained to those call sites. The problem does not reshape architecture or propagate widely beyond the components that parse JSON.
Closest to 'serious trap' (t7). The misconception field identifies the core trap: developers assume null return means null input, not a parse failure — meaning invalid JSON silently passes as valid decoded data. This contradicts the intuition from most other parsing functions in PHP and other languages that raise errors or return false on failure, making this a serious behavioural contradiction that competent developers routinely get wrong.
Also Known As
TL;DR
Explanation
json_decode($json, true) parses a JSON string, returning an associative array (true) or stdClass object (false/null). Unlike unserialize(), it cannot instantiate arbitrary PHP objects or invoke magic methods, making it safe for untrusted input. Always check json_last_error() === JSON_ERROR_NONE after decoding, or use JSON_THROW_ON_ERROR (PHP 7.3+) to throw a JsonException on malformed input. Use json_encode() with JSON_THROW_ON_ERROR on the output side.
Common Misconception
Why It Matters
Common Mistakes
- Not checking json_last_error() after decoding — null from a malformed JSON string is indistinguishable from JSON null.
- Using the second argument (assoc=true) inconsistently — mixing object and array access patterns.
- Not setting JSON_THROW_ON_ERROR flag (PHP 7.3+) — eliminates the need to manually check json_last_error().
- Not validating the decoded structure — a valid JSON string may decode to a type or shape the application does not expect.
Code Examples
// Silent failure on invalid JSON:
$data = json_decode($input);
$name = $data->name; // Fatal error or null — json_last_error() not checked
// Safe:
$data = json_decode($input, flags: JSON_THROW_ON_ERROR);
// JsonException thrown on invalid JSON
// Always pass true for associative array (avoids stdClass)
$data = json_decode($json, true);
// Check for errors
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \InvalidArgumentException('Invalid JSON: ' . json_last_error_msg());
}
// PHP 7.3+ — throw on error
try {
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
throw new \InvalidArgumentException('Invalid JSON', previous: $e);
}
// Encode with useful flags
$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);