Работа с JSON: кодирование PHP массивов и объектов
Основные техники кодирования 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 превратит его в объект с числовыми строками-ключами.