PHP 8.3: Added json_validate
function
PHP 8.3 adds a new function named json_validate
that returns true
or false
whether the given string is a valid JSON string.
Prior to PHP 8.3, the only way to determine if a given string is a valid JSON string was to attempt to decode it, and see if any errors were emitted. The new json_validate
function uses the same underlying JSON parser PHP uses, but consumes less memory and processing as json_decode
only analyzes the string without constructing any decoded value.
Applications that have strong measures to prevent invalid JSON strings from being processed may not find the new json_validate
function useful, because a json_validate
call immediately followed by a json_decode
can slightly increase the execution time as the JSON string is analyzed twice, and there is a higher chance of the input JSON string being valid JSON in the place.
Applications that accept user-provided JSON, or connect remote JSON APIs may find the best use of the new json_validate
, because there is a significant chance of encountering invalid JSON strings.
json_validate('[1, 2, 3]'); // true
json_validate('{1, 2, 3]'); // false
json_validate
function synopsis
/**
* Validates a given string to be valid JSON.
*
* @param string $json String to validate
* @param int $depth Set the maximum depth. Must be greater than zero.
* @param int $flags Bitmask of flags.
* @return bool True if $json contains a valid JSON string, false otherwise.
*/
function json_validate(string $json, int $depth = 512, int $flags = 0): bool {
}
json_validate
is declared in the global namespace.- Validation errors can be retrieved with the existing
json_last_error
andjson_last_error_msg
functions. - See
json_validate
flags for a list of accepted flags. Passing an invalid flag throws anError
exception. - For usage examples, see
json_validate
examples.
It is possible to polyfill this function with user-land PHP code, using json_decode
(which consumes memory, and thus has no intrinsic value-add).
json_validate
accepted flags ($flags
)
json_validate
function accepts a bit-mask of flags for its third parameter $flags
. While it is possible that additional flags will be added later in newer PHP versions, JSON_INVALID_UTF8_IGNORE
is the only accepted flag for the $flags
parameter.
JSON_INVALID_UTF8_IGNORE
is an existing PHP constant (since PHP 7.2) accepted by the json_decode
function as well. When passed, json_decode
and json_validate
functions ignore UTF-8 characters in the given string.
json_validate('[1, 2, 3]', flags: JSON_INVALID_UTF8_IGNORE); // true
json_validate("[\"\xc1\xc1\",\"a\"]"); // false
json_validate("[\"\xc1\xc1\",\"a\"]", flags: JSON_INVALID_UTF8_IGNORE); // true
The snippet above uses named parameters added in PHP 8.0 and Hexadecimal character escape sequences.
Passing an unaccepted value results in a ValueError
exception:
json_validate('', flags: JSON_BIGINT_AS_STRING);
json_validate(): Argument #3 ($flags) must be a valid flag (allowed flags: JSON_INVALID_UTF8_IGNORE).
json_validate
validation errors
json_validate()
function does not return the validation error code (such as syntax errors, depth exhaustion, unsupported type, etc). However, existing existing json_last_error
and json_last_error_msg
functions can be used to determine the validation error.
json_validate(""); // false
json_last_error(); // 4
json_last_error_msg(); // "Syntax error"
json_validate("null"); // true
json_last_error(); // 0
json_last_error_msg(); // "No error"
Similar to
json_decode
andjson_encode
functions,json_validate
mutates the application state by storing the error code of the last operation, makingjson_validate
not a pure function. While this should have no significant impact on most PHP applications, there can be edge cases including race conditions on certain novelty PHP runners that serve multiple concurrent requests on the same thread.
Usage examples
The following are some usage examples of the new json_validate
function. They do not check whether the json_validate
function is available on the running PHP versions. Applications/packages that need to support PHP versions older than PHP 8.3 might need to either conditionally use the json_validate
function, or polyfill it in user-land PHP code.
Validating a given JSON string
json_validate($_GET['json']);
Validating a given JSON string and throwing an exception
This mimics the JSON_THROW_ON_ERROR
flag, introduced in PHP 7.3.
if (json_validate($_GET['json']) === false) {
throw new \JsonException(json_last_error_msg(), json_last_error());
}
Replace existing JSON validation with new json_validate
function
- $value = json_decode($_GET['json'], flags: JSON_THROW_ON_ERROR);
+ if (!json_validate($_GET['json'])) {
+ throw new \JsonException(json_last_error_msg(), json_last_error());
+ }
+ $value = json_decode($_GET['json']);
User-land polyfill
json_validate()
function's internal implementation consumes less memory and processing, and it is the main advantage of the json_validate
function. It is possible to polyfill it in user-land PHP code by observing the errors accumulated in a json_decode
code, but it provides no memory/processing improvement over the actual implementation.
This polyfill uses
json_decode
function followed by an error detection. Applications that calljson_validate
before callingjson_decode
this effectively means valid JSON strings are decoded twice. See Double-decode Cost for more information.
if (!function_exists('json_validate')) {
function json_validate(string $json, int $depth = 512, int $flags = 0): bool {
if ($flags !== 0 && $flags !== \JSON_INVALID_UTF8_IGNORE) {
throw new \ValueError('json_validate(): Argument #3 ($flags) must be a valid flag (allowed flags: JSON_INVALID_UTF8_IGNORE)');
}
if ($depth <= 0 ) {
throw new \ValueError('json_validate(): Argument #2 ($depth) must be greater than 0');
}
\json_decode($json, null, $depth, $flags);
return \json_last_error() === \JSON_ERROR_NONE;
}
}
The above snippet should be functional in all PHP 8.0 and later. If the \ValueError
exceptions were to be replaced with a different type of exception, the polyfill will be compatible with PHP >= 7.3.
Double-decode cost
Note that the polyfill above calls json_decode
function inside, which fully decodes the provided JSON string. If the application decodes the JSON string after the json_validate
call, this effectively doubles the processing resources because the polyfilled json_validate
function calls json_decode
.
The optimal use cases for json_validate
include validating the user-provided JSON strings before passing it to another system and storing them. If the application calls json_decode
right after a json_validate
call, it might be more efficient to call json_decode
and detect error conditions.
Backwards Compatibility Impact
json_validate()
is a new function added in PHP 8.3. Existing PHP applications that declare a json_validate
function in the global namespace will encounter a function redeclare error on PHP 8.3.
This function can be implemented in user-land PHP code, albeit it cannot provide the actual memory/processing benefits the actual json_validate
function provides.