JSON в PHP 7.3: отделяем ошибку разбора от значения null

2 мин чтения

Разбираем JSON в PHP 7.3 через JSON_THROW_ON_ERROR и отдельно проверяем, подходит ли структура данных приложению.

Разбор JSON не равен проверке документа
  1. JSON_THROW_ON_ERRORРазбор сообщает о некорректном JSON исключением
  2. Полученное значениеnull может быть корректным результатом
  3. СтруктураПроверяем поля, типы и обязательные значения

Json_decode вернул null. В документе действительно было null или JSON не удалось разобрать? Флаг JSON_THROW_ON_ERROR помогает различить эти случаи: ошибка разбора станет исключением. После успешного разбора работа не заканчивается — нужно ещё проверить поля, типы и допустимые значения.

Разбор JSON и проверка полей

<?php
function readOptions(string $raw): array {
    $value = json_decode($raw, true, 32, JSON_THROW_ON_ERROR);
    if (!is_array($value) || !isset($value['limit'])
        || !is_int($value['limit']) || $value['limit'] < 1
        || $value['limit'] > 100) {
        throw new InvalidArgumentException('Нужен limit от 1 до 100');
    }
    return ['limit' => $value['limit']];
}
try {
    $options = readOptions('{"limit":20}');
    echo $options['limit'];
} catch (JsonException $error) {
    echo 'Повреждённый JSON';
} catch (InvalidArgumentException $error) {
    echo 'Неверная структура настроек';
}

Функция возвращает только поле, которое ожидает приложение. Синтаксически правильный JSON ещё не описывает пригодные настройки: строка вместо числа, отрицательный предел и отсутствие ключа требуют собственной проверки. Внешний обработчик может связать эти две категории с разными сообщениями журнала, сохранив для клиента понятный ответ. Сам исходный документ записывать в журнал без разбора опасно: он может содержать секретные параметры.

Версия PHP и ограничения разбора

Флаг появился именно в PHP 7.3, поэтому пример нельзя переносить в PHP 7.2 без изменения обработки ошибок. JsonException сообщает об ошибках JSON, а не обо всех возможных проблемах приложения. Ограничение глубины задаёт допустимую вложенность, но не заменяет предел размера тела запроса. Строки должны иметь корректную кодировку UTF-8; режим исключений не исправляет повреждённые байты автоматически.

В примере глубина равна тридцати двум уровням. Для своей структуры данных выберите подходящую глубину. Не добавляйте одновременно множество флагов для подавления ошибок кодировки: тогда часть повреждённых данных может незаметно измениться. Если преобразование необходимо, опишите его отдельно и проверяйте результат до передачи бизнес-логике. Исключение удобно обрабатывать там, где ещё известен источник документа и можно сформировать контролируемый ответ.

Как проверить результат

Передайте объект с limit: 20, строковый limit, пустой объект, null и оборванный JSON. Число двадцать должен вернуть только первый вариант. Затем проверьте слишком большую вложенность и неверный UTF-8. Ошибку разбора и ошибку структуры нужно различать, чтобы было понятно, что именно исправить во входных данных.

Источники и дальнейшее чтение