Гид по технологиям

JSON в PHP: чтение, запись и лучшие практики

7 min read PHP Обновлено 23 Dec 2025
JSON в PHP: чтение, запись и лучшие практики
JSON в PHP: чтение, запись и лучшие практики

Логотип PHP

Быстрые ссылки

  • Reading JSON Data

  • Handling Parsing Errors

  • Serializing data to JSON

  • Bringing JSON to Your Application’s Domain Layer

JSON — один из самых распространённых форматов сериализации данных. Он появился в экосистеме JavaScript (JSON — JavaScript Object Notation) и стал де-факто стандартом для веб-API и конфигурационных файлов.

PHP содержит встроенную поддержку JSON. Раньше это была отдельная расширяемая библиотека, но начиная с PHP 8.0 расширение JSON всегда активно и не может быть отключено.

Основные определения

  • JSON: текстовый формат для представления структурированных данных.
  • Сериализация: преобразование структуры данных в строку для хранения или передачи.
  • Десериализация: обратный процесс — преобразование строки в структуру данных приложения.

Чтение JSON (json_decode)

Для разбора JSON используйте функцию

json_decode()

Её сигнатура:

json_decode(string $json, bool|null $associative=null, int $depth=512, int $flags=0) : mixed;

Простейший вызов — передать строку JSON без дополнительных аргументов. Пример:

{"foo": "bar"}

По умолчанию это декодируется в экземпляр PHP-класса

stdClass

с публичным свойством

foo

равным

bar

.

Если вы хотите получить ассоциативный массив, передайте

true

в параметр

$associative

:

["foo" => "bar"]

Параметр

$depth

определяет максимальную глубину вложенности. При превышении этой глубины функция вернёт

null

и не попытается разобрать данные.

Параметр

$flags

принимает битовую маску опций, влияющих на поведение парсера. Полный список флагов и их описание содержится в официальной документации PHP.

Важно: по умолчанию json_decode возвращает null при ошибке, что не позволяет отличить корректный JSON, содержащий значение null, от ошибки разбора. Начиная с PHP 7.3 используется флаг JSON_THROW_ON_ERROR, позволяющий выбрасывать исключение при ошибке.

Обработка ошибок при парсинге

По умолчанию:

json_decode()

вернёт

null

при передаче некорректной JSON-строки. Это проблематично, потому что JSON может легитимно содержать значение null.

Начиная с PHP 7.3, добавлен флаг

JSON_THROW_ON_ERROR

. Передайте его в параметр

$flags

чтобы получить исключение при ошибке разбора:

json_decode("['malformed json", true, 512, JSON_THROW_ON_ERROR);

Для удобства и читабельности в PHP 8 можно использовать именованные аргументы:

json_decode(json: "['malformed json", flags: JSON_THROW_ON_ERROR);

Пример с обработкой исключения:

try {
    $data = json_decode($jsonString, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    // Логи, метрики, информирование пользователя/клиента
    error_log('JSON decode error: ' . $e->getMessage());
    throw $e; // или другая стратегия обработки
}

Примечание: JsonException доступен начиная с соответствующей версии PHP; проверяйте совместимость при поддержке старых платформ.

Запись данных в JSON (json_encode)

Для сериализации значений PHP в JSON используется функция

json_encode()

Её сигнатура:

json_encode(mixed $value, int $flags=0, int $depth=512) : string|false;

PHP принимает любые значения, кроме ресурсов. Типы автоматически приводятся в соответствующее представление JSON. Объекты и ассоциативные массивы станут JSON-объектами; скаляры — прямыми JSON-значениями.

Обратите внимание: порядок опциональных параметров у json_encode отличается от json_decode (flags идёт перед depth), что часто вызывает путаницу.

Основные флаги кодирования, которые часто полезно знать:

  • JSON_FORCE_OBJECT — заставляет числовые массивы преобразовываться в JSON-объекты. Полезно, когда нужно гарантировать объект даже для пустого массива.
  • JSON_PRETTY_PRINT — форматирует вывод с отступами и переводами строк для удобства чтения людьми.
  • JSON_PRESERVE_ZERO_FRACTION — сохраняет дробную часть у чисел типа 0.0 (иначе может получиться 0).
  • JSON_NUMERIC_CHECK — преобразует числовые строки в числа в выходном JSON (например, “234.5” -> 234.5).
  • JSON_PARTIAL_OUTPUT_ON_ERROR — пытается продолжить сериализацию, подставляя допустимые значения, если встречаются несерилизуемые элементы.

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

$data = ['id' => 1, 'title' => "Пример"];
$json = json_encode($data, JSON_PRETTY_PRINT | JSON_PRESERVE_ZERO_FRACTION);

Важно: не включайте в JSON ресурсы или замыкания — они не сериализуемы и вызовут ошибку. Для частичных ошибок можно использовать JSON_PARTIAL_OUTPUT_ON_ERROR, но это снижет предсказуемость результата.

Сериализация доменных объектов (JsonSerializable)

В сложных бэкендах вы чаще всего будете кодировать объекты прикладного уровня (доменные объекты) для HTTP-ответов. По умолчанию json_encode() перечисляет только публичные свойства объекта:

class BlogPost {

protected int $Id = 1;

public string $Title = "Example";

}

// produces '{"Title": "Example"}'

$json = json_encode(new BlogPost());

Защищённые и приватные свойства недоступны автоматически, поэтому для контроля вывода используйте интерфейс

JsonSerializable

.

Интерфейс требует реализации метода

jsonSerialize()

, который вызывается при сериализации экземпляра:

class BlogPost implements JsonSerializable {

    protected int $Id = 1;

    public string $Title = "Example";

    public function jsonSerialize() {
        return [
            "Id" => $this->Id,
            "Title" => $this->Title
        ];
    }
}

// produces '{"Id": 1, "Title": "Example"}'

$json = json_encode(new BlogPost());

jsonSerialize() может возвращать любую структуру, которую PHP умеет сериализовать в JSON — массив, объект, строку, число и т.д. Это даёт гибкость: скрывать поля, вычислять значения на лету, композиция сущностей.

Практические рекомендации и шаблоны

Важно:

  • Всегда валидируйте входной JSON при приёме из ненадёжных источников.
  • Используйте JSON_THROW_ON_ERROR для явной обработки ошибок и логирования.
  • Для публичных API чётко документируйте схему (пример: OpenAPI/JSON Schema).

Рекомендации по флагам:

  • Для человекочитаемых конфигураций используйте JSON_PRETTY_PRINT.
  • Для сохранения нулевой дробной части чисел используйте JSON_PRESERVE_ZERO_FRACTION.
  • Для совместимости с внешними сервисами проверяйте, нужен ли JSON_NUMERIC_CHECK — он может неожиданно превратить строки.

Шаблон сериализации доменного объекта:

class Presenter implements JsonSerializable {
    private $model;
    public function __construct($model) { $this->model = $model; }
    public function jsonSerialize() {
        return [
            'id' => $this->model->getId(),
            'title' => $this->model->getTitle(),
            // поля, проверка прав доступа
        ];
    }
}

Когда это не работает — типичные случаи и обходные пути

  1. Некорректная кодировка (не UTF-8). JSON требует UTF-8; если строка содержит байты в другой кодировке, парсер вернёт ошибку. Решение: перекодировать в UTF-8.
  2. Большие числа (bigint) теряют точность при преобразовании в float/double. Решение: хранить как строку или использовать библиотеки для работы с большими числами.
  3. Циклические ссылки в объектах. json_encode вызовет ошибку. Решение: вручную преобразовать структуру в деревообразную (убрать циклы) или вернуть идентификаторы.
  4. Не сериализуемые значения (resource, Closure). Решение: фильтрация перед сериализацией или замена значений на допустимые представления.

Альтернативные подходы:

  • Для строго типизированного обмена используйте MessagePack или protobuf (бинарные форматы) — меньше места и быстрее, но требуют схемы.
  • Для валидации входящих JSON применяйте JSON Schema или библиотеки валидации.

Безопасность и приватность

  • Не включайте в JSON чувствительные поля (пароли, токены) без явной необходимости. Фильтруйте данные на уровне модели/презентера.
  • Логи с необработанным JSON могут раскрыть PII — маскируйте данные перед записью.
  • Для GDPR/защиты данных документируйте какие поля сохраняются/передаются и по каким основаниям.

Совместимость и миграция

  • Проверяйте минимальную требуемую версию PHP при использовании JSON_THROW_ON_ERROR и именованных аргументов.
  • При миграции с старой версии PHP тестируйте поведение json_encode/json_decode на реальных payload’ах и в логах.

Чек-листы по ролям

Разработчик API:

  • Использовать JsonSerializable для доменных объектов.
  • Документировать схему ответа.
  • Поддерживать JSON_PRETTY_PRINT для конфигураций.

Backend-инженер:

  • Проверять кодировки (UTF-8).
  • Логировать ошибки JsonException.
  • Фильтровать чувствительные данные.

QA-инженер:

  • Писать тесты, покрывающие ошибки парсинга.
  • Проверять пограничные случаи: пустые массивы, null, большие числа.

Критерии приёмки

  • Все публичные эндпоинты возвращают корректный JSON с заголовком Content-Type: application/json.
  • На некорректный JSON система возвращает контролируемую ошибку (400/422) и логируется причина.
  • Сериализуются все поля, требуемые спецификацией API; чувствительные поля отсутствуют.

Тестовые случаи и примеры для unit-тестов

Пример теста с PHPUnit:

public function testDecodeValidJson() {
    $json = '{"foo": "bar"}';
    $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
    $this->assertIsArray($data);
    $this->assertEquals('bar', $data['foo']);
}

public function testDecodeInvalidJsonThrows() {
    $this->expectException(JsonException::class);
    json_decode("['malformed json", true, 512, JSON_THROW_ON_ERROR);
}

Примеры кода — обработка ошибок и ответ в контроллере

try {
    $payload = json_decode($request->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    return new JsonResponse(['error' => 'Invalid JSON payload'], 400);
}

// Использование презентера
$responseData = (new PostPresenter($postModel))->jsonSerialize();
return new JsonResponse($responseData);

Ментальные модели и эвристики

  • “Явный > неявный”: предпочитайте явную обработку ошибок (исключения), а не молчаливое возвращение null.
  • “Презентер = контракт”: используйте презентер/DTO для формирования стабильного API-контракта, а не напрямую json_encode() доменной модели.
  • “Флаги как конфигурация”: воспринимайте флаги json_encode/json_decode как способ конфигурировать контракт вывода.

Примеры ошибок и их разбор

Ошибка: json_decode вернул null, но JSON не содержит null. Возможные причины:

  • Некорректная кодировка (не UTF-8).
  • Синтаксическая ошибка в JSON.
  • Превышена глубина парсинга.

Решение: логировать json_last_error_msg() или использовать JSON_THROW_ON_ERROR и перехватывать JsonException.

Часто задаваемые вопросы

Что лучше: получать массив или объект при json_decode?

Ассоциативный массив (associative=true) удобен для доступа по ключам и тестов. Объект stdClass полезен, если вы ожидаете объектную модель и не планируете модифицировать структуру.

Стоит ли всегда включать JSON_PRETTY_PRINT?

Нет — для сетевого обмена обычно предпочтительна минифицированная строка. JSON_PRETTY_PRINT полезен для конфигурационных файлов и локальной отладки.

Как хранить большие числовые идентификаторы?

Если числа могут превышать точность PHP float, храните их как строки или используйте библиотеки для работы с большими числами.

Краткое резюме

  • Используйте json_decode() и json_encode() корректно — проверяйте флаги и глубину.
  • Включайте JSON_THROW_ON_ERROR для явной обработки ошибок.
  • Реализуйте JsonSerializable для доменных объектов, чтобы контролировать публичный контракт API.
  • Фильтруйте чувствительные данные и соблюдайте требования по кодировке (UTF-8).

Важно: тестируйте поведение на реальных payload’ах и не полагайтесь на поведение по умолчанию для безопасности и согласованности API.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство