Что такое JSON и зачем он вообще нужен
JSON (JavaScript Object Notation) — это текстовый формат для хранения и передачи данных. Он не привязан к какому‑то одному языку: его одинаково понимают JavaScript, PHP, Python, Java и почти всё остальное.
В вебе JSON используют, чтобы:
- передавать данные между фронтендом и бэкендом;
- хранить простые структуры в файлах или в базе данных;
- обмениваться данными с API (Яндекс, соцсети, платёжные системы и т. п.);
- делать конфиги, которые должны быть человекочитаемыми.
Почему выбирают именно JSON:
- Читаемость. Обычный текст, можно открыть в любом редакторе.
- Лёгкость. Нет лишних тегов, как в XML.
- Универсальность. Почти все языки умеют его читать и писать.
- Простота структуры. Есть только объекты, массивы, строки, числа, булевы значения и
null.
Как JSON выглядит и что ему соответствует в PHP
В JSON есть два главных контейнера:
- Объект
{ "key": "value" }→ в PHP это ассоциативный массив или объектstdClass. - Массив
[ "a", "b", "c" ]→ в PHP это индексированный массив.
Пример JSON:
{ "user": "alex", "active": true, "roles": ["admin", "editor"], "meta": { "last_login": 1710000000 } }
После json_decode($json, true) в PHP получится:
[ 'user' => 'alex', 'active' => true, 'roles' => ['admin', 'editor'], 'meta' => [ 'last_login' => 1710000000, ], ]
Если декодировать без true, будет объект: $data->user, $data->meta->last_login.
Кодирование: превращаем PHP в JSON — json_encode()
Функция: json_encode($value, $flags = 0, $depth = 512)
Простой пример
$data = [ 'name' => 'Иван', 'age' => 30, 'active' => true, ]; $json = json_encode($data); echo $json; // {"name":"\u0418\u0432\u0430\u043d","age":30,"active":true}
Видишь \u0418...? Это UTF‑8 в экранированном виде. Чтобы кириллица была сразу читаемой, нужен флаг:
$json = json_encode( $data, JSON_UNESCAPED_UNICODE ); echo $json; // {"name":"Иван","age":30,"active":true}
Полезные флаги
JSON_UNESCAPED_UNICODE— русские буквы не превращаются в\uXXXX.JSON_PRETTY_PRINT— делает JSON с отступами (удобно для логов и отладки).JSON_THROW_ON_ERROR— при ошибке выбрасывает исключение вместо возвратаfalse(PHP 7.3+).
Пример с двумя флагами:
$json = json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT );
Декодирование: превращаем JSON в PHP — json_decode()
Функция: json_decode($json, $assoc = false, $depth = 512, $flags = 0)
$assoc = true→ результат: ассоциативный массив.$assoc = false→ результат: объектstdClass.
Пример с массивом (чаще удобнее)
$json = '{"name":"Иван","age":30}'; $data = json_decode($json, true); var_dump($data['name']); // string(8) "Иван"
Пример с объектом
$dataObj = json_decode($json); var_dump($dataObj->name); // string(8) "Иван"
Почему нельзя проверять ошибки по null
Это частая ошибка. json_decode может вернуть null в двух случаях:
- JSON был валидным и на самом деле равен
null(json_decode('null') === null). - Произошла ошибка декодирования.
Поэтому правильная проверка — через json_last_error():
$data = json_decode($json, true); if ($data === null && json_last_error() !== JSON_ERROR_NONE) { // тут ошибка $msg = json_last_error_msg(); }
То же самое с json_encode: он возвращает false при ошибке, и тогда тоже нужно смотреть json_last_error().
Частые ошибки и почему они возникают
| Ошибка | Почему | Как избежать |
|---|---|---|
json_encode вернул false |
В данных есть ресурс (PDO‑соединение, файл), либо строка не UTF‑8, либо слишком глубокая вложенность | Не кодировать ресурсы; проверять кодировку; использовать json_last_error() |
Кириллица в виде \u04xx |
Не указан JSON_UNESCAPED_UNICODE |
Добавлять этот флаг всегда, если есть русский текст |
json_decode вернул null, но кажется, что ошибка |
Забыли проверить json_last_error(); null — валидный JSON |
Проверять ошибку явно, а не только по null |
| Смешаны массивы и объекты | В одном месте assoc=true, в другом нет — код становится запутанным |
Выбрать единый стиль проекта (чаще массивы) и придерживаться его |
Безопасные обёртки: чтобы не писать проверки каждый раз
Для PHP 7 удобно сделать две простые функции.
Безопасное кодирование
function jsonEncodeSafe(array $data): string { $json = json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR ); return $json; }
С флагом JSON_THROW_ON_ERROR при ошибке сразу будет исключение JsonException, которое можно ловить через try/catch.
Безопасное декодирование
<
function jsonDecodeSafe(string $json, bool $assoc = true) { $data = json_decode($json, $assoc); if ($data === null && json_last_error() !== JSON_ERROR_NONE) { throw new \RuntimeException( 'Ошибка JSON: ' . json_last_error_msg() ); } return $data; }
Теперь можно писать:
try { $data = jsonDecodeSafe($inputJson); } catch (\RuntimeException $e) { // логирование, ответ клиенту и т. п. }
Пример: полный цикл «запрос → валидация → ответ»
Подходит для API.
header('Content-Type: application/json; charset=utf-8'); try { $input = file_get_contents('php://input'); if ($input === false) { throw new \RuntimeException('Не удалось прочитать тело запроса'); } $data = jsonDecodeSafe($input, true); // простая валидация if (!isset($data['message']) || !is_string($data['message'])) { throw new \InvalidArgumentException('Поле message обязательно и должно быть строкой'); } // какая-то логика (например, запись в БД через PDO) $response = [ 'success' => true, 'message' => 'Принято: ' . $data['message'], 'timestamp' => time(), ]; echo jsonEncodeSafe($response); } catch (\Exception $e) { http_response_code(400); echo json_encode([ 'success' => false, 'error' => $e->getMessage(), ], JSON_UNESCAPED_UNICODE); }
Практические советы
- Всегда используй
JSON_UNESCAPED_UNICODEпри кодировании, если в данных есть русский текст. - Выбирай один стиль (массивы или объекты) и придерживайся его в проекте. Для интеграции и API чаще удобнее массивы (
assoc=true). - Не доверяй входящему JSON. Всегда валидируй структуру и типы полей после декодирования.
- Логируй ошибки JSON вместе с
json_last_error_msg()— это сильно ускоряет отладку. - Для отладки используй
JSON_PRETTY_PRINT, но в продакшене лучше без него (меньше размер ответа).
Мини‑пример: сохраняем JSON в поле MySQL и читаем обратно
Допустим ты хочешь хранить простую структуру в одном JSON‑поле.
// запись $pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'user', 'pass'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dataToSave = [ 'ip' => $_SERVER['REMOTE_ADDR'] ?? '', 'browser' => $_SERVER['HTTP_USER_AGENT'] ?? '', ]; $jsonToDb = jsonEncodeSafe($dataToSave); $stmt = $pdo->prepare('INSERT INTO logs (json_data) VALUES (:json)'); $stmt->execute([':json' => $jsonToDb]); // чтение $stmt = $pdo->prepare('SELECT json_data FROM logs WHERE id = :id'); $stmt->execute([':id' => 1]); $row = $stmt->fetch(PDO::FETCH_ASSOC); $restored = jsonDecodeSafe($row['json_data'], true); var_dump($restored['ip']);
Когда JSON не нужен
- Если структура очень сложная и нужна строгая схема с валидацией — иногда лучше отдельные колонки в БД.
- Если данные бинарные (картинки, файлы) — JSON не подходит.
- Если критична максимальная скорость и объём — бинарные форматы (MessagePack, Protobuf) могут быть эффективнее.
Но для большинства веб‑задач в PHP JSON — самый простой и надёжный вариант.
