PHP JSON: преобразование данных, примеры и практические советы
Работа с JSON в PHP: кодирование и декодирование
Основным способом преобразования данных в формат JSON и обратно в PHP являются функции json_encode и json_decode. Они поддерживаются всеми современными версиями PHP и обеспечивают двустороннюю конвертацию между переменными PHP (массивами, объектами, скалярами) и строками JSON.
Как закодировать данные в JSON?
$data = ["name" => "Иван", "age" => 30, "skills" => ["PHP", "MySQL", "JavaScript"]];
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
echo $json;
{
"name": "Иван",
"age": 30,
"skills": [
"PHP",
"MySQL",
"JavaScript"
]
}
Флаг JSON_UNESCAPED_UNICODE сохраняет кириллицу без экранирования, а JSON_PRETTY_PRINT добавляет отступы для читаемости.
Как декодировать JSON строку в массив?
$jsonString = '{"name":"Иван","age":30,"skills":["PHP","MySQL","JavaScript"]}';
$array = json_decode($jsonString, true);
var_dump($array);
array(3) {
["name"]=>
string(8) "Иван"
["age"]=>
int(30)
["skills"]=>
array(3) {
[0]=>
string(3) "PHP"
[1]=>
string(5) "MySQL"
[2]=>
string(10) "JavaScript"
}
}
Второй аргумент true заставляет функцию возвращать ассоциативный массив, а не объект по умолчанию.
Типичные ошибки:
- При использовании json_decode без проверки на null - функция возвращает null при ошибке, а также при значении JSON "null". Рекомендуется проверять json_last_error().
- Кодировка строки должна быть UTF-8. Любые другие кодировки приведут к ошибке JSON_UNICODE_ERROR.
- При кодировании объектов, не реализующих JsonSerializable, PHP преобразует только публичные свойства. Защищённые и приватные поля будут потеряны.
Альтернативные подходы и нюансы
Как сохранить читаемый JSON в файл?
$data = ['product' => 'Ноутбук', 'price' => 49999.99];
$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
file_put_contents('product.json', $json);
Файл product.json будет содержать отформатированный JSON с отступами.
Как декодировать глубоко вложенный JSON с проверкой ошибок?
$json = file_get_contents('complex.json');
$result = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$errorMsg = json_last_error_msg();
// логирование или другая обработка ошибки
exit("Ошибка декодирования: $errorMsg");
}
// работа с $result
Проблема: декодирование большого JSON может привести к переполнению памяти.
Решение: использовать потоковый JSON-парсер, например json_decode с ограничением глубины через флаг JSON_OBJECT_AS_ARRAY
Как закодировать объект с приватными полями?
class User implements JsonSerializable {
private $name;
private $age;
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}
public function jsonSerialize() {
return [
'name' => $this->name,
'age' => $this->age
];
}
}
$user = new User('Анна', 25);
echo json_encode($user, JSON_UNESCAPED_UNICODE);
{"name":"Анна","age":25}
Интерфейс JsonSerializable позволяет контролировать, какие данные будут включены в JSON.
Расширенные примеры кодирования и декодирования JSON
Пример 1: Кодирование с разными флагами
$data = [
'company' => 'ООО "Ромашка"',
'employees' => 150,
'departments' => ['IT', 'HR', 'Sales'],
'isActive' => true,
'nullValue' => null
];
// Без флагов (экранирование Unicode, слэшей)
echo "Без флагов:\n";
echo json_encode($data) . "\n\n";
// С флагами для читаемости
$options = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT;
echo "С читаемыми флагами:\n";
echo json_encode($data, $options);
Без флагов:
{"company":"\u041e\u041e\u041e \u0022\u0420\u043e\u043c\u0430\u0448\u043a\u0430\u0022","employees":150,"departments":["IT","HR","Sales"],"isActive":true,"nullValue":null}
С читаемыми флагами:
{
"company": "ООО \"Ромашка\"",
"employees": 150,
"departments": [
"IT",
"HR",
"Sales"
],
"isActive": true,
"nullValue": null
}
Пример 2: Декодирование в объект stdClass
$json = '{"title":"PHP 8","pages":450,"authors":["John","Jane"]}';
$obj = json_decode($json); // ассоциативный false по умолчанию
echo $obj->title . "\n";
echo $obj->authors[0];
PHP 8 John
Пример 3: Обработка ошибок декодирования
$badJson = '{"name": "Вася", age: 30}'; // ключ age не в кавычках
$decoded = json_decode($badJson);
if (json_last_error() !== JSON_ERROR_NONE) {
$errorCode = json_last_error();
$errorMsg = json_last_error_msg();
echo "Код ошибки: $errorCode\n";
echo "Сообщение: $errorMsg\n";
}
Код ошибки: 4 Сообщение: Syntax error, malformed JSON
Пример 4: Глубоко вложенный JSON и ограничение глубины
$deepJson = '{"a":{"b":{"c":{"d":"test"}}}}';
// По умолчанию глубина не ограничена (но ограничена памятью)
$decoded = json_decode($deepJson, true, 512, JSON_OBJECT_AS_ARRAY);
echo $decoded['a']['b']['c']['d']; // test
Пример 5: Кодирование объекта DateTime
$date = new DateTime('2025-01-15 14:30:00');
echo json_encode($date); // ошибка: object of class DateTime could not be converted to JSON
// Решение: преобразовать в строку или использовать JsonSerializable
class DateTimeWrapper implements JsonSerializable {
private $datetime;
public function __construct(DateTime $dt) {
$this->datetime = $dt;
}
public function jsonSerialize() {
return $this->datetime->format('Y-m-d H:i:s');
}
}
$wrapper = new DateTimeWrapper(new DateTime('2025-01-15 14:30:00'));
echo json_encode($wrapper, JSON_UNESCAPED_UNICODE);
"2025-01-15 14:30:00"
Пример 6: Сериализация массива с нелатинскими ключами
$arr = ['ключ1' => 'значение1', 'ключ2' => 'значение2'];
echo json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT);
{"ключ1":"значение1","ключ2":"значение2"}
Флаг JSON_FORCE_OBJECT гарантирует, что пустой массив будет представлен как объект, а не как пустой массив.
Пример 7: Декодирование JSON с числовыми ключами
$json = '{"0":"a","1":"b","2":"c"}';
$arr = json_decode($json, true);
var_dump($arr);
array(3) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
string(1) "c"
}
Пример 8: Потоковая обработка JSON (для больших файлов)
// Использование json_decode не подходит для очень больших файлов.
// Рекомендуется использовать специализированные парсеры, например,
// расширение JSONCoder или библиотеку seld/jsonlint.
// Пример с базовым разбиением на чанки (упрощённо):
$handle = fopen('large.json', 'r');
$buffer = '';
while (!feof($handle)) {
$buffer .= fread($handle, 8192);
// здесь нужно парсить частично (требуется сторонняя реализация)
}
fclose($handle);