Работа с JSON: кодирование PHP массивов и объектов

Раздел: Работа с JSON в PHP -> Кодирование JSON

Основные техники кодирования JSON в PHP

Как наиболее эффективно преобразовать данные PHP в JSON с учетом всех особенностей?

Функция json_encode является стандартным средством для кодирования данных. Для максимальной надежности рекомендуется использовать ее с набором опций, таких как JSON_UNESCAPED_UNICODE, JSON_UNESCAPED_SLASHES, а также JSON_THROW_ON_ERROR для обработки ошибок.

<?php
$data = [
    'name' => 'Иван',
    'age' => 30,
    'skills' => ['PHP', 'JavaScript', 'JSON']
];

$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
echo $json;
?>

Php данные в json (преобразование данных в json на php)

{"name":"Иван","age":30,"skills":["PHP","JavaScript","JSON"]}

Php json encode (php: json_encode() - кодирование в json)

В этом примере флаг JSON_UNESCAPED_UNICODE сохраняет кириллические символы в читаемом виде, а JSON_THROW_ON_ERROR преобразует ошибки кодирования в исключения, что упрощает отладку.

Типичная проблема: при отсутствии флага Unicode кириллица кодируется в escape-последовательности вида \u0438\u0432. Решение: всегда добавлять JSON_UNESCAPED_UNICODE, если требуется читаемый вывод. Другая проблема: если в данных присутствуют ресурсы или типы, не поддерживаемые JSON (например, объекты без интерфейса JsonSerializable), json_encode вернет false. При использовании JSON_THROW_ON_ERROR будет выброшено исключение JsonException, которое можно перехватить.

Как быстро превратить массив в JSON без дополнительной настройки?

<?php
$arr = ['apple', 'banana', 'cherry'];
$json = json_encode($arr);
echo $json;
?>
["apple","banana","cherry"]

Этот вариант подходит для простых структур, когда не требуется поддержка Unicode или обработка слэшей. Однако следует учитывать, что по умолчанию русские символы будут экранированы.

Проблема: потеря читаемости кириллицы. Решение: использовать флаг из основного варианта.

Как сделать JSON-строку удобной для чтения человеком?

<?php
$data = ['user' => 'Анна', 'roles' => ['admin', 'editor']];
$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
echo $json;
?>
{
    "user": "Анна",
    "roles": [
        "admin",
        "editor"
    ]
}

Флаг JSON_PRETTY_PRINT добавляет отступы и переносы строк, что удобно для отладки или сохранения в файл.

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

Как представить объект PHP в формате JSON?

<?php
class User {
    public $name;
    public $age;
    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
}
$user = new User('Пётр', 25);
$json = json_encode($user, JSON_UNESCAPED_UNICODE);
echo $json;
?>
{"name":"Пётр","age":25}

json_encode автоматически преобразует публичные свойства объекта в ассоциативный массив и затем в JSON. Защищенные и приватные свойства игнорируются.

Проблема: если объект имеет приватные или защищенные поля, они не попадут в JSON. Для полного контроля следует реализовать интерфейс JsonSerializable.

Как проверить, успешно ли выполнено кодирование?

<?php
$data = ['value' => fopen('php://memory', 'r')];
$json = json_encode($data);
if ($json === false) {
    $error = json_last_error_msg();
    echo "Ошибка кодирования: $error";
} else {
    echo $json;
}
?>
Ошибка кодирования: Malformed UTF-8 characters, possibly incorrectly encoded

Функция json_last_error_msg возвращает понятное описание ошибки. Этот метод подходит, когда по какой-то причине нельзя использовать исключения.

Проблема: легко забыть проверить возвращаемое значение. Рекомендуется использовать либо JSON_THROW_ON_ERROR, либо явную проверку на false.

Как закодировать массив с числовыми ключами как объект, а не как массив?

<?php
$array = [0 => 'ноль', 1 => 'один'];
$json_object = json_encode($array, JSON_FORCE_OBJECT);
$json_array = json_encode($array);
echo "Объект: $json_object\n";
echo "Массив: $json_array";
?>
Объект: {"0":"ноль","1":"один"}
Массив: ["ноль","один"]

Флаг JSON_FORCE_OBJECT принудительно превращает массив в объект. Это может быть полезно при кодировании ассоциативных массивов, где нужна согласованность структуры.

Проблема: если массив начинается с 0 и последователен, по умолчанию он становится массивом JSON. При использовании JSON_FORCE_OBJECT ключи становятся строками, что может сломать ожидания клиента.

Как преобразовать строки, содержащие числа, в числовой тип?

<?php
$data = ['id' => '123', 'price' => '45.67'];
$json = json_encode($data, JSON_NUMERIC_CHECK);
echo $json;
?>
{"id":123,"price":45.67}

Флаг JSON_NUMERIC_CHECK автоматически конвертирует строки, выглядящие как числа, в числа. Это удобно при получении данных из форм, где все является строками.

Проблема: может изменить тип данных неожиданно, например, если строка '0123' станет числом 123 (теряется ведущий ноль). Следует применять флаг осознанно.

Как предоставить собственное JSON-представление объекта?

<?php
class Car implements JsonSerializable {
    private $brand;
    private $year;
    private $color;
    public function __construct($brand, $year, $color) {
        $this->brand = $brand;
        $this->year = $year;
        $this->color = $color;
    }
    public function jsonSerialize() {
        return [
            'mark' => $this->brand,
            'year' => $this->year,
            'color' => $this->color,
            'age' => date('Y') - $this->year
        ];
    }
}
$car = new Car('Toyota', 2020, 'red');
echo json_encode($car, JSON_UNESCAPED_UNICODE);
?>
{"mark":"Toyota","year":2020,"color":"red","age":5}

Интерфейс JsonSerializable позволяет определить, какие данные будут переданы в JSON. Это полезно для скрытия приватных полей или добавления вычисляемых значений.

Проблема: если не реализовать интерфейс, приватные поля игнорируются. Также требуется внимательно возвращать данные, поддерживающие json_encode (массивы, скаляры).

Можно ли создать JSON вручную без использования встроенных функций?

<?php
$data = ['name' => 'Иван', 'age' => 30];
$json = '{"name":"' . $data['name'] . '","age":' . $data['age'] . '}';
echo $json;
?>
{"name":"Иван","age":30}

Ручная сборка возможна для очень простых структур, но крайне не рекомендуется из-за риска неправильного экранирования, неверных типов и инъекций. Намного безопаснее и проще использовать json_encode.

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

Пример с частичным выводом при ошибках: JSON_PARTIAL_OUTPUT_ON_ERROR

Этот флаг позволяет получить JSON даже если некоторые значения не могут быть закодированы. Некорректные значения заменяются на null.

Пример
<?php
$data = [
    'valid' => 'строка',
    'invalid' => fopen('php://memory', 'r'),
    'nested' => ['also valid' => 123]
];
$json = json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_UNESCAPED_UNICODE);
echo $json;
?>
{"valid":"строка","invalid":null,"nested":{"also valid":123}}

Как видно, ресурс не удалось сериализовать, и он заменен на null. Остальные данные корректны. Это удобно для логирования или частичной передачи данных.

Пример рекурсивной сериализации с JsonSerializable

Когда объект содержит другие объекты, которые также реализуют JsonSerializable, кодирование происходит рекурсивно.

Пример
<?php
class Address implements JsonSerializable {
    private $city, $street;
    public function __construct($city, $street) {
        $this->city = $city;
        $this->street = $street;
    }
    public function jsonSerialize() {
        return ['city' => $this->city, 'street' => $this->street];
    }
}
class Person implements JsonSerializable {
    private $name;
    private $address;
    public function __construct($name, Address $address) {
        $this->name = $name;
        $this->address = $address;
    }
    public function jsonSerialize() {
        return ['name' => $this->name, 'address' => $this->address];
    }
}
$person = new Person('Мария', new Address('Москва', 'Тверская'));
echo json_encode($person, JSON_UNESCAPED_UNICODE);
?>
{"name":"Мария","address":{"city":"Москва","street":"Тверская"}}

Метод jsonSerialize в Person возвращает массив, содержащий объект Address. При кодировании этого массива json_encode вызывает jsonSerialize у объекта Address, создавая вложенную структуру.

Влияние флагов на экранирование слэшей и Unicode

По умолчанию json_encode экранирует обратный слэш и символы Unicode. С помощью флагов можно управлять этим.

Пример
<?php
$data = ['path' => '/home/user/file.txt', 'text' => 'Привет мир'];
echo "Без флагов:\n" . json_encode($data) . "\n\n";
echo "С JSON_UNESCAPED_SLASHES:\n" . json_encode($data, JSON_UNESCAPED_SLASHES) . "\n\n";
echo "С JSON_UNESCAPED_UNICODE:\n" . json_encode($data, JSON_UNESCAPED_UNICODE) . "\n\n";
echo "С обоими флагами:\n" . json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n";
?>
Без флагов:
{"path":"\/home\/user\/file.txt","text":"\u041f\u0440\u0438\u0432\u0435\u0442 \u043c\u0438\u0440"}

С JSON_UNESCAPED_SLASHES:
{"path":"/home/user/file.txt","text":"\u041f\u0440\u0438\u0432\u0435\u0442 \u043c\u0438\u0440"}

С JSON_UNESCAPED_UNICODE:
{"path":"\/home\/user\/file.txt","text":"Привет мир"}

С обоими флагами:
{"path":"/home/user/file.txt","text":"Привет мир"}

Обратите внимание: без флагов слэши экранируются, а Unicode кодируется в escape-последовательности. Флаг JSON_UNESCAPED_SLASHES убирает экранирование слэшей. JSON_UNESCAPED_UNICODE оставляет кириллицу читаемой.

Преобразование больших чисел с JSON_BIGINT_AS_STRING

В PHP целые числа могут превышать максимальное значение, поддерживаемое JSON (2^53). При кодировании такие числа теряют точность. Флаг JSON_BIGINT_AS_STRING сохраняет их как строки.

Пример
<?php
$bigInt = 12345678901234567890;
$data = ['big' => $bigInt];
echo "Без флага:\n" . json_encode($data) . "\n";
echo "С JSON_BIGINT_AS_STRING:\n" . json_encode($data, JSON_BIGINT_AS_STRING);
?>
Без флага:
{"big":12345678901234568000}
С JSON_BIGINT_AS_STRING:
{"big":"12345678901234567890"}

Без флага число 12345678901234567890 было округлено до 12345678901234568000 из-за ограничения 64-битного представления. Использование флага сохраняет точность за счет строки.

Кодирование пустых массивов: объект или массив

Пустой массив [] по умолчанию кодируется как []. Но если нужно получить пустой объект {}, можно использовать JSON_FORCE_OBJECT. Однако это повлияет и на непустые массивы. Для выборочного контроля лучше использовать приведение массива к объекту.

Пример
<?php
$emptyArray = [];
$nonEmpty = ['a' => 1, 'b' => 2];
echo "Пустой массив:\n" . json_encode($emptyArray) . "\n";
echo "С JSON_FORCE_OBJECT:\n" . json_encode($emptyArray, JSON_FORCE_OBJECT) . "\n";
echo "Непустой ассоциативный массив:\n" . json_encode($nonEmpty, JSON_FORCE_OBJECT);
?>
Пустой массив:
[]
С JSON_FORCE_OBJECT:
{}
Непустой ассоциативный массив:
{"a":1,"b":2}

Для пустого массива JSON_FORCE_OBJECT создает пустой объект, что может быть необходимо для совместимости с некоторыми API. Для непустого ассоциативного массива результат не меняется (он и так объект). Однако если массив числовой и непустой, JSON_FORCE_OBJECT превратит его в объект с числовыми строками-ключами.

Преобразование данных в JSON на PHP - comments

En
Php данные в json (php)