PHP 8.3 introdujo json_validate(), una función que comprueba si una cadena es JSON válido sin decodificarla. La diferencia con json_decode() es importante: no construye ninguna estructura de datos en memoria, por lo que consume muchos menos recursos cuando solo te interesa saber si el JSON es válido, no su contenido.
Sintaxis básica
<?php
// Disponible desde PHP 8.3
var_dump(json_validate('{"nombre":"Ana","edad":28}')); // bool(true)
var_dump(json_validate('[1,2,3]')); // bool(true)
var_dump(json_validate('"cadena válida"')); // bool(true)
var_dump(json_validate('{clave: valor}')); // bool(false) ? sin comillas
var_dump(json_validate('{"a":1,}')); // bool(false) ? coma final
var_dump(json_validate('')); // bool(false)
?>
Acepta un segundo parámetro para limitar la profundidad máxima (por defecto 512), igual que json_decode():
<?php
$jsonProfundo = str_repeat('{"a":', 10) . '1' . str_repeat('}', 10);
var_dump(json_validate($jsonProfundo, 5)); // bool(false) ? supera el límite
var_dump(json_validate($jsonProfundo, 15)); // bool(true)
?>
Comparación con json_decode()
<?php
$json = file_get_contents('/ruta/a/fichero-grande.json');
// Opción 1: json_decode() + comprobación de error
// Construye toda la estructura en memoria aunque luego la deseches
$datos = json_decode($json, true);
$esValido = ($datos !== null || json_last_error() === JSON_ERROR_NONE);
// Opción 2: json_validate() en PHP 8.3
// Sin construcción de estructura en memoria
$esValido = json_validate($json);
// Solo si es válido, entonces decodificamos
if ($esValido) {
$datos = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
}
?>
Combinar json_validate() con JsonException
<?php
function procesarPayload(string $body): array
{
if (!json_validate($body)) {
throw new InvalidArgumentException('El cuerpo de la petición no es JSON válido');
}
// Aquí ya podemos decodificar con confianza
return json_decode($body, true, 512, JSON_THROW_ON_ERROR);
}
// En un controlador de API
try {
$datos = procesarPayload(file_get_contents('php://input'));
// procesar $datos...
} catch (InvalidArgumentException $e) {
http_response_code(400);
echo json_encode(['error' => $e->getMessage()]);
}
?>
Uso en validación de formularios y webhooks
<?php
// Webhook de pago: validar antes de procesar
function recibirWebhook(): void
{
$payload = file_get_contents('php://input');
if (!json_validate($payload)) {
http_response_code(400);
exit('Payload inválido');
}
$datos = json_decode($payload, true, 512, JSON_THROW_ON_ERROR);
// procesar evento de pago...
}
// Validar campo JSON guardado en base de datos
function esCampoJsonValido(?string $valor): bool
{
if ($valor === null || $valor === '') {
return false;
}
return json_validate($valor);
}
?>
Polyfill para PHP 8.1 y PHP 8.2
Si tu proyecto todavía no usa PHP 8.3, puedes crear un polyfill con json_decode() y JSON_THROW_ON_ERROR:
<?php
if (!function_exists('json_validate')) {
function json_validate(string $json, int $depth = 512, int $flags = 0): bool
{
if ($depth <= 0) {
throw new ValueError('json_validate(): Argument #2 ($depth) must be greater than 0');
}
try {
json_decode($json, true, $depth, JSON_THROW_ON_ERROR | $flags);
return true;
} catch (JsonException) {
return false;
}
}
}
?>
El polyfill es funcionalmente equivalente, aunque sí construye la estructura en memoria. Para PHP 8.1/8.2 es la única opción disponible. Instalar el paquete symfony/polyfill-php83 via Composer también incluye esta función de forma transparente.
Cuándo usar json_validate() y cuándo no
- Úsala cuando necesites validar JSON antes de procesarlo, especialmente con payloads grandes de APIs o webhooks donde la validación puede fallar frecuentemente.
- No la uses si inmediatamente después vas a llamar a
json_decode()con todos los datos: estás recorriendo la cadena dos veces. En ese caso, llama directamente ajson_decode()conJSON_THROW_ON_ERRORy captura la excepción.
La documentación oficial de json_validate() incluye el benchmark de consumo de memoria frente a json_decode() y los flags disponibles.
