Декодирование JSON в PHP с помощью json_decode: подробный разбор
Декодирование JSON в PHP: функция json_decode
Наиболее эффективный способ декодирования JSON в PHP
Использование функции json_decode() с флагом JSON_THROW_ON_ERROR (доступно с PHP 7.3). Этот подход позволяет обрабатывать ошибки декодирования через исключения, что упрощает контроль потока выполнения и делает код чище.
$json = '{"name":"Иван","age":30}';
try {
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
echo "Данные получены: ";
print_r($data);
} catch (JsonException $e) {
echo "Ошибка декодирования JSON: " . $e->getMessage();
}
Php json decode (php: json_decode() - декодирование json)
Данные получены: Array ( [name] => Иван [age] => 30 )
Типичные проблемы и их решения:
- Некорректная кодировка: JSON должен быть в UTF-8. Для очистки используйте флаги
JSON_INVALID_UTF8_IGNOREилиJSON_INVALID_UTF8_SUBSTITUTE. - Слишком большая глубина вложенности: увеличьте параметр
depth(по умолчанию 512). - Большие целые числа теряют точность: применяйте флаг
JSON_BIGINT_AS_STRING. - Синтаксические ошибки в JSON: проверяйте строку на лишние запятые, неэкранированные кавычки, неправильные типы кавычек (только двойные).
Как декодировать JSON строку в ассоциативный массив?
Передайте второй аргумент true для получения ассоциативного массива вместо объекта stdClass.
$json = '{"city":"Москва","year":2023}';
$result = json_decode($json, true);
print_r($result);
Array ( [city] => Москва [year] => 2023 )
Если флаг не указан, по умолчанию возвращается объект stdClass. Ошибка может возникнуть, если в JSON встречаются ключи, недопустимые для свойств объекта (например, начинающиеся с цифры). Решение: всегда указывайте true для работы с массивами.
Как обработать некорректный JSON без исключений?
Проверьте возвращаемое значение на null и используйте json_last_error() для получения кода ошибки.
$json = '{invalid}';
$data = json_decode($json);
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
echo 'Ошибка: ' . json_last_error_msg();
} else {
print_r($data);
}
Ошибка: Syntax error
Важно разделять случай, когда JSON содержит строку "null" (корректное значение) и ошибку декодирования. Проверка $data === null может быть ложной, если JSON равен "null". Дополнительно проверяйте json_last_error().
Как декодировать с сохранением больших целых чисел?
Большие числа (больше PHP_INT_MAX) теряют точность при преобразовании в int. Используйте флаг JSON_BIGINT_AS_STRING.
$json = '{"big":123456789012345678901234567890}';
$data = json_decode($json, true, 512, JSON_BIGINT_AS_STRING);
echo $data['big']; // выводится как строка
123456789012345678901234567890
Без флага число будет округлено до float, что приведёт к потере точности. Решение: всегда применяйте JSON_BIGINT_AS_STRING при работе с потенциально большими числами.
Как ограничить глубину декодирования?
Третий параметр depth задаёт максимальную глубину вложенности (по умолчанию 512).
$json = '{"a":{"b":{"c":1}}}';
$data = json_decode($json, true, 2); // глубина 2
var_dump($data);
NULL (из-за превышения глубины)
При недостаточной глубине функция возвращает null. Решение: увеличивайте глубину или проверяйте ошибку JSON_ERROR_DEPTH.
Как декодировать JSON с управляющими символами или некорректной кодировкой?
Используйте флаги JSON_INVALID_UTF8_IGNORE (пропустить) или JSON_INVALID_UTF8_SUBSTITUTE (заменить на символ U+FFFD).
$json = "{\"text\":\"\xc3\x28\"}"; // некорректный UTF-8
$data = json_decode($json, true, 512, JSON_INVALID_UTF8_SUBSTITUTE);
echo $data['text'];
� (заменяющий символ)
Без флага декодирование вернёт null с ошибкой JSON_ERROR_UTF8. Решение: предварительно очищайте строку или используйте флаги.
Как проверить, является ли строка валидным JSON, без полного декодирования?
Можно вызвать json_decode() с флагом JSON_THROW_ON_ERROR и перехватить исключение, или проверить json_last_error(). Но полное декодирование всё равно происходит. Эффективный способ - парсить через json_decode и проверять ошибку.
function isValidJson($string) {
json_decode($string);
return json_last_error() === JSON_ERROR_NONE;
}
var_dump(isValidJson('{"valid":true}'));
var_dump(isValidJson('not json'));
bool(true) bool(false)
Метод неэффективен для очень больших строк, так как парсинг всё равно выполняется. Для быстрой проверки можно использовать регулярные выражения, но они не дают полной гарантии.
Расширенные примеры работы с json_decode
Пример 1: Декодирование сложной вложенной структуры с различными флагами
Показано использование нескольких флагов одновременно: JSON_THROW_ON_ERROR, JSON_BIGINT_AS_STRING и JSON_OBJECT_AS_ARRAY (эквивалент второго параметра true).
$json = '{
"id": 12345678901234567890,
"user": {
"name": "Алексей",
"attributes": [1, 2, 3]
}
}';
try {
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
echo "ID: " . $data['id'] . " (тип: " . gettype($data['id']) . ")\n";
print_r($data['user']);
} catch (JsonException $e) {
echo "Ошибка: " . $e->getMessage();
}
ID: 12345678901234567890 (тип: string)
Array
(
[name] => Алексей
[attributes] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
)
Обратите внимание, что id сохранился как строка благодаря JSON_BIGINT_AS_STRING. Без флага он превратился бы в float с потерей точности.
Пример 2: Рекурсивное преобразование stdClass в массив
Если нужно гарантированно получить многомерный массив даже при отсутствии флага true, можно использовать рекурсивную функцию.
function objectToArray($data) {
if (is_object($data)) {
$data = get_object_vars($data);
}
if (is_array($data)) {
return array_map(__FUNCTION__, $data);
}
return $data;
}
$json = '{"a":{"b":[1,2,{"c":3}]}}';
$obj = json_decode($json);
$arr = objectToArray($obj);
print_r($arr);
Array
(
[a] => Array
(
[b] => Array
(
[0] => 1
[1] => 2
[2] => Array
(
[c] => 3
)
)
)
)
Функция get_object_vars работает только для public свойств. Если объект содержит private или protected свойства, они не будут включены. Для stdClass это безопасно.
Пример 3: Декодирование JSONP (JSON с callback)
Иногда внешние API возвращают JSONP: callback({...}). Необходимо удалить вызов функции и скобки, затем декодировать внутренний JSON.
$jsonp = 'myFunction({"result":"ok","count":42})';
preg_match('/\((.*)\)$/', $jsonp, $matches);
if (isset($matches[1])) {
$json = $matches[1];
$data = json_decode($json, true);
print_r($data);
} else {
echo "Неверный формат JSONP";
}
Array
(
[result] => ok
[count] => 42
)
Регулярное выражение предполагает, что callback содержит только буквы, цифры и подчёркивания. Если внутри JSON есть скобки, выражение может сработать некорректно. Для надёжности используйте разбор строки вручную или библиотеку.
Пример 4: Обработка BOM (Byte Order Mark) в JSON строке
Файлы JSON могут содержать BOM в начале (например, UTF-8 BOM: \xEF\xBB\xBF). Необходимо удалить его перед декодированием.
$jsonWithBom = "\xEF\xBB\xBF{\"key\":\"value\"}";
$json = ltrim($jsonWithBom, "\xEF\xBB\xBF");
$data = json_decode($json, true);
print_r($data);
Array ( [key] => value )
Без удаления BOM функция json_decode вернёт null с ошибкой синтаксиса. Решение: всегда проверяйте и удаляйте BOM, особенно при чтении из файлов.
Пример 5: Декодирование с проверкой типов полученных данных
Иногда требуется убедиться, что определённое поле имеет ожидаемый тип (например, число, а не строка). Используйте is_int, is_string и т.д.
$json = '{"age":"25"}';
$data = json_decode($json, true);
if (isset($data['age'])) {
// Принудительное преобразование, если нужно число
$age = (int)$data['age'];
echo $age; // 25
}
25
Исходное значение "25" - строка. Если приложение ожидает целое число, может потребоваться явное приведение. Для строгих проверок используйте filter_var($data['age'], FILTER_VALIDATE_INT).
Пример 6: Декодирование с пользовательским обработчиком ошибок
Можно создать функцию-обёртку, которая логирует все ошибки декодирования.
function safeJsonDecode($json, $assoc = false, $depth = 512, $flags = 0) {
$result = json_decode($json, $assoc, $depth, $flags);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('JSON decode error: ' . json_last_error_msg() . ' for input: ' . substr($json, 0, 100));
return null;
}
return $result;
}
$data = safeJsonDecode('{"valid":true}');
var_dump($data);
object(stdClass)#1 (1) { ["valid"]=> bool(true) }
Обёртка не выбрасывает исключения, а логирует ошибку и возвращает null. Это удобно для пакетной обработки, когда нужно продолжить выполнение.