PHP 8.3: Добавлена функция json_validate

Источник: «PHP 8.3: Added json_validate function»
В PHP 8.3 добавлена новая функция названая json_validate, возвращающая true или false в зависимости от того, является ли заданная строка допустимой JSON-строкой.

До PHP 8.3 единственным способом определить, является ли заданная строка допустимой JSON-строкой, была попытка её декодирования и проверки наличия каких-либо ошибок. Новая функция json_validate использует тот же базовый синтаксический анализатор JSON, что и PHP, но потребляет меньше памяти и ресурсов процессора чем json_decode, поскольку только анализирует строку, не создавая никакого декодированного значения.

Приложения, в которых предусмотрены строгие меры для предотвращения обработки недопустимых JSON-строк, могут найти новую функцию не столько полезной. Поскольку вызов json_validate, за которым следует json_decode, может немного увеличить время выполнения, так как JSON-строка будет анализироваться дважды. Существует большая вероятность, что входящая строка будет допустимой JSON-строкой.

Приложения, которые принимают предоставленный пользователем JSON или подключаются к удалённым JSON API-интерфейсам, могут наилучшим способом использовать новый параметр json_validate, поскольку существует значительная вероятность обнаружения недопустимых JSON-строк.

json_validate('[1, 2, 3]'); // true
json_validate('{1, 2, 3]'); // false

Описание функции json_validate

/**
* Проверяет заданную строку на соответствие JSON.
*
* @param string $json Строка для проверки
* @param int $depth Установите максимальную глубину. Должно быть больше нуля.
* @param int $flags Битовая маска флагов.
* @return bool true если $json содержит допустимую JSON-строку, иначе false.
*/

function json_validate(string $json, int $depth = 512, int $flags = 0): bool {
}

Принимаемые флаги json_validate ($flags)

Функция json_validate принимает битовую маску флагов в качестве третьего параметра $flags. Хотя возможно, что дополнительные флаги будут добавлены в более новых версиях PHP. На данный момент JSON_INVALID_UTF8_IGNORE единственный допустимый флаг для параметра $flags.

JSON_INVALID_UTF8_IGNORE — константа PHP (начиная с PHP 7.2), которую также принимает функция json_decode.

При передаче этого флага функциям json_decode и json_ignore, они игнорируют символы UTF-8 в заданной строке.

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

В приведённом выше фрагменте используются именованные параметры, добавленные в PHP 8.0, и escape-последовательности шестнадцатеричных символов.

Ошибки валидации json_validate

Функция json_validate не возвращает код ошибки валидации (например, синтаксическая ошибка, слишком большая глубина, неподдерживаемый тип и т.д.). Однако для определения ошибки валидации можно использовать существующие функции json_last_error и json_last_error_msg.

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"

Подобно функциям json_decode и json_encode, json_validate изменяет состояние приложения, сохраняя код ошибки последней операции, что делает json_validate не чистой функцией. Хотя это не должно оказывать существенного влияния на большинство PHP-приложений, могут быть пограничные случаи, в том числе условия гонки на некоторых новых PHP раннерах, которые обслуживают несколько одновременных запросов в одном потоке.

Примеры использования

Ниже приведены некоторые примеры использования новой функции json_decode. Они не проверяют, доступна ли функция json_validate в работающей версии PHP. Приложениям/пакетам, которым необходимо поддерживать версии старше PHp 8.3, может потребоваться либо условное использование json_validate, либо использование полифилла в пользовательском PHP коде.

Валидация заданной JSON-строки

json_validate($_GET['json']);

Валидация заданной JSON-строки и выдача исключения

Это имитирует флаг JSON_THROW_ON_ERROR представленный в PHP 7.3.

if (json_validate($_GET['json']) === false) {
throw new \JsonException(json_last_error_msg(), json_last_error());
}

Замена существующей валидации JSON новой функцией json_validate

- $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']);

Полифилл

Внутренняя реализация функции json_validate() потребляет меньше ресурсов, и это главное преимущество функции json_validate. Можно использовать полифилл в пользовательском PHP-коде, наблюдая за ошибками накопленными в json-decode, но это не даёт преимуществ в использовании памяти/вычислений по сравнению с фактической реализацией.

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;
}
}

Приведённый выше фрагмент должен работать в PHP 8.0 и более поздних версиях. Если заменить \ValueError другим типом исключения, то полифилл будет совместим с PHP >= 7.3.

Влияние обратной совместимости

json_validate() — новая функция добавленная в PHP 8.3. Существующие PHP-приложения, объявляющие функцию json_validate в глобальном пространстве имён, столкнутся с ошибкой повторного объявления функции в PHP 8.3.

Эта функция может быть реализована в пользовательском PHP-коде, хотя она не может дать преимуществ памяти/обработке, которые даёт актуальная функция json_validate.

Дополнительные материалы

Предыдущая Статья

Laravel: переносим Контроллер в Сервисный Класс с внедрением

Следующая Статья

PHP 8.3: unserialize() обновление ошибки E_NOTICE до E_WARNING