json_validate() — Native JSON Validation (PHP 8.3)
debt(d7/e1/b3/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints.tools list is not specified, so no automated tool is cited from metadata. The misuse pattern — calling json_validate() then json_decode() incorrectly, or using it as a schema validator — is a logic-level mistake that won't surface as a syntax or lint error. It requires code review to spot the wrong branch (decoding on false) or a functional test to catch silent failures from missing JSON_THROW_ON_ERROR. No compiler or default linter catches this.
Closest to 'one-line patch or single-call swap' (e1). The quick_fix explicitly describes replacing the old json_decode()+json_last_error() validation pattern with a single 'if (!json_validate($s))' guard clause. This is a straightforward, localised one-line replacement at each call site — no structural refactor required.
Closest to 'localised tax' (b3). The choice applies to web, cli, and queue-worker contexts per applies_to, but each usage is an independent call-site guard clause. It does not impose cross-cutting architectural obligations. The main ongoing tax is remembering to pair it correctly with json_decode(), which is a per-developer, per-call-site awareness cost rather than a system-wide burden.
Closest to 'notable trap' (t5). The misconception field explicitly states the canonical trap: developers assume json_validate() replaces json_decode() and then omit the decode entirely, or decode in the wrong branch. This is a documented, well-known gotcha (it only checks validity, not usability), and several common_mistakes reinforce it — especially the error of decoding on the false branch and missing JSON_THROW_ON_ERROR. It's a trap most developers hit once, placing it squarely at t5.
Also Known As
TL;DR
Explanation
Before PHP 8.3, the only way to validate JSON was to call json_decode() and check json_last_error() — which allocated memory to build the decoded value even though you only wanted to know if the string was valid. json_validate() parses the JSON structure without building a PHP data structure, making it significantly faster and less memory-intensive for large payloads. It returns true/false. It accepts the same optional depth and flags arguments as json_decode(). This is ideal for webhook handlers, API input validation, and message queue consumers that need to validate incoming JSON before forwarding to a decoder.
Common Misconception
Why It Matters
Common Mistakes
- Calling json_validate() and then immediately calling json_decode() on failure — json_validate() returns false on invalid JSON, so the decode should only happen in the true branch.
- Using json_validate() as a substitute for schema validation — it only checks JSON syntax, not whether the structure matches your expected schema.
- Not specifying a depth limit for untrusted input — deeply nested JSON can cause stack overflows; json_validate($input, depth: 10) is safer for external data.
- Forgetting JSON_THROW_ON_ERROR on json_decode() after validation — json_decode() can still return null for valid JSON ('null' is valid JSON), so throw-on-error prevents silent failures.
Code Examples
<?php
// ❌ Using json_decode() purely for validation — wasteful
function handleWebhook(string $body): void
{
$data = json_decode($body, true); // Allocates full PHP array
if (json_last_error() !== JSON_ERROR_NONE) {
throw new InvalidArgumentException('Invalid JSON');
}
// Now decode again (or use $data — but you allocated it twice if validating first)
processPayload($data);
}
<?php
// ✅ PHP 8.3 — validate cheaply, decode only once
function handleWebhook(string $body): void
{
if (!json_validate($body)) {
throw new InvalidArgumentException('Invalid JSON payload');
}
// Decode only after confirming validity
$data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
processPayload($data);
}
// With depth limit for untrusted input
if (!json_validate($untrustedInput, depth: 5)) {
return false;
}