Типы данных JSON в PHP: от простого к сложному

Раздел: Основы JSON -> Типы данных

Основы работы с типами данных JSON в PHP

JSON (JavaScript Object Notation) поддерживает шесть типов данных: строку (string), число (number), объект (object), массив (array), логическое значение (boolean) и null. В PHP этим типам соответствуют строки, целые и вещественные числа, ассоциативные массивы и объекты, индексированные массивы, булевы значения и NULL. Для преобразования между PHP и JSON используются функции json_encode() и json_decode(). Ниже рассмотрены эффективные приёмы и альтернативные подходы.

Основное решение: стандартное кодирование и декодирование

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


$data = [
    'name' => 'Иван',
    'age' => 30,
    'is_active' => true,
    'tags' => ['php', 'json'],
    'metadata' => null
];

// Кодирование с флагами: экранирование Unicode, pretty print (для отладки)
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
echo $json;
  
{
    "name": "Иван",
    "age": 30,
    "is_active": true,
    "tags": ["php", "json"],
    "metadata": null
}
  

Декодирование с преобразованием в ассоциативный массив (второй параметр true):


$decoded = json_decode($json, true);
var_dump($decoded);
  
array(5) {
  ["name"]=> string(8) "Иван"
  ["age"]=> int(30)
  ["is_active"]=> bool(true)
  ["tags"]=> array(2) {
    [0]=> string(3) "php"
    [1]=> string(4) "json"
  }
  ["metadata"]=> NULL
}
  

При ошибках кодирования/декодирования следует проверять json_last_error() и json_last_error_msg().

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

Реализовать интерфейс JsonSerializable, который требует метод jsonSerialize().


class User implements JsonSerializable {
    public $name;
    protected $password;
    
    public function __construct($name, $password) {
        $this->name = $name;
        $this->password = $password;
    }
    
    public function jsonSerialize(): mixed {
        return [
            'name' => $this->name,
            // пароль не включаем
        ];
    }
}

$user = new User('Алексей', 'secret123');
echo json_encode($user, JSON_UNESCAPED_UNICODE);
  
{"name":"Алексей"}
  

Проблема: если забыть реализовать JsonSerializable, json_encode вернёт пустой объект или false для protected/private свойств.

Решение: всегда явно реализовывать интерфейс или делать нужные свойства public.

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

В PHP 8.3 появилась функция json_validate(). Раньше использовали json_decode() с проверкой ошибки.


$jsonString = '{"key": "value"}';

// Способ 1 (PHP 8.3+)
if (json_validate($jsonString)) {
    echo 'Валидный JSON';
}

// Способ 2 (универсальный)
$decoded = json_decode($jsonString);
if (json_last_error() === JSON_ERROR_NONE) {
    echo 'Валидный JSON';
}
  

Проблема: json_validate не сообщает о причине ошибки. Для деталей всё равно нужен json_last_error.

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

Использовать json_decode() с флагом JSON_OBJECT_AS_ARRAY (по умолчанию false) и затем привести к нужному классу через ручное заполнение или сторонние библиотеки. В PHP нет встроенного гидратора.


class Product {
    public string $title;
    public float $price;
}

$json = '{"title":"Книга","price":499.50}';
$stdObj = json_decode($json); // объект stdClass
$product = new Product();
$product->title = $stdObj->title;
$product->price = $stdObj->price;
  

Проблема: при больших наборах данных ручное присваивание неудобно. Используют сторонние библиотеки (Symfony Serializer, JMS Serializer).

Как обработать большие целые числа, не теряя точность?

По умолчанию json_decode преобразует большие числа в float, что может потерять точность. Флаг JSON_BIGINT_AS_STRING оставляет числа строками.


$bigJson = '{"id": 12345678901234567890}';
$decoded = json_decode($bigJson, false, 512, JSON_BIGINT_AS_STRING);
var_dump($decoded->id); // string(20) "12345678901234567890"
  

Ошибка: если забыть флаг, число будет преобразовано во float с потерей знаков.

Как кодировать данные с кириллицей без экранирования?

Флаг JSON_UNESCAPED_UNICODE отключает экранирование символов Unicode.


echo json_encode(['привет'], JSON_UNESCAPED_UNICODE);
// ["привет"]
  

Без флага результат: ["\u043f\u0440\u0438\u0432\u0435\u0442"]

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

Флаг JSON_FORCE_OBJECT - если массив пуст, он станет пустым объектом. Для непустых массивов поведение не меняется.


echo json_encode([], JSON_FORCE_OBJECT); // {}
echo json_encode(['a'], JSON_FORCE_OBJECT); // ["a"]
  

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

По умолчанию json_encode возвращает false, если встречает рекурсивные объекты. Флаг JSON_PARTIAL_OUTPUT_ON_ERROR позволяет кодировать то, что возможно, заменяя проблемные части на null.


$obj = new stdClass();
$obj->self = $obj;
echo json_encode($obj, JSON_PARTIAL_OUTPUT_ON_ERROR);
// {"self":null}
  

Проблема: потеря данных - не всегда желаемое поведение. Рекомендуется избегать циклических ссылок в данных для JSON.

Типичные ошибки и их решения

Ошибка: json_encode возвращает false при кодировании ресурсов (например, потока).

Решение: преобразовать ресурс в строку или массив данных до кодирования.

Ошибка: json_decode возвращает null для строки 'null'.

Решение: отличить настоящий null от ошибки парсинга можно через проверку json_last_error().

Ошибка: проблема с глубиной вложенности (по умолчанию 512 уровней, параметр depth).

Решение: увеличить depth в вызове json_decode или json_encode.

Расширенные примеры работы с типами данных JSON

Набор демонстраций, охватывающий нестандартные ситуации и комбинации флагов.

1. Кодирование ассоциативного массива с числовыми ключами

Пример

$arr = [0 => 'a', 1 => 'b', '2' => 'c']; // ключи-строки, содержащие числа, тоже считаются числовыми
echo json_encode($arr); // ["a","b","c"]

$mixed = ['foo' => 'bar', 0 => 'baz'];
echo json_encode($mixed); // {"foo":"bar","0":"baz"} - нечисловой ключ превращает в объект

2. Декодирование с сохранением типа float

Пример

$json = '{"value": 1.5e10}';
$decoded = json_decode($json);
var_dump($decoded->value); // float(15000000000)

// Принудительно как строка:
$decoded2 = json_decode($json, false, 512, JSON_BIGINT_AS_STRING);
// но JSON_BIGINT_AS_STRING применяется только к целым, не к float

3. Сериализация объекта DateTime

Пример

$date = new DateTime('2025-03-15 14:30:00');
echo json_encode($date); // {"date":"2025-03-15 14:30:00.000000","timezone_type":3,"timezone":"UTC"}
// Лучше предварительно форматировать:
echo json_encode(['created' => $date->format('c')], JSON_UNESCAPED_UNICODE);
// {"created":"2025-03-15T14:30:00+00:00"}

4. Кодирование вложенных объектов с приватными свойствами через JsonSerializable

Пример

class Address implements JsonSerializable {
    private string $city;
    private string $zip;
    
    public function __construct($city, $zip) {
        $this->city = $city;
        $this->zip = $zip;
    }
    
    public function jsonSerialize(): mixed {
        return ['city' => $this->city, 'zip' => $this->zip];
    }
}

class Person implements JsonSerializable {
    private string $name;
    private Address $address;
    
    public function __construct($name, Address $address) {
        $this->name = $name;
        $this->address = $address;
    }
    
    public function jsonSerialize(): mixed {
        return ['name' => $this->name, 'address' => $this->address];
    }
}

$person = new Person('Елена', new Address('Москва', '101000'));
echo json_encode($person, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
{
    "name": "Елена",
    "address": {
        "city": "Москва",
        "zip": "101000"
    }
}

5. Обработка ошибки при декодировании повреждённого JSON

Пример

$badJson = '{"key": "value"';
$result = json_decode($badJson);
if (json_last_error() !== JSON_ERROR_NONE) {
    echo 'Ошибка: ' . json_last_error_msg(); // Syntax error, malformed JSON
}

6. Использование JSON_NUMERIC_CHECK для преобразования строковых чисел в числа

Пример

$json = '{"id":"123","price":"45.67"}';
$decoded = json_decode($json, true, 512, JSON_NUMERIC_CHECK);
var_dump($decoded['id']); // int(123)
var_dump($decoded['price']); // float(45.67)
// Осторожно: строки вида '123abc' останутся строками

7. Кодирование с флагом JSON_INVALID_UTF8_IGNORE / JSON_INVALID_UTF8_SUBSTITUTE

Пример

$data = ['name' => "\xB1\x31"]; // некорректный UTF-8
$json = json_encode($data, JSON_INVALID_UTF8_SUBSTITUTE);
echo $json; // {"name":"\ufffd1"} - заменено на символ замены
// Если использовать JSON_INVALID_UTF8_IGNORE - строка будет пропущена

8. Декодирование JSON-массива объектов с преобразованием в класс (ручной гидратор)

Пример

$json = '[{"id":1,"name":"A"},{"id":2,"name":"B"}]';
$items = json_decode($json); // массив stdClass
$objects = array_map(function($std) {
    $obj = new stdClass();
    $obj->id = $std->id;
    $obj->name = $std->name;
    // здесь можно создать инстанс нужного класса
    return $obj;
}, $items);
var_dump($objects);

9. Пакетная проверка валидности нескольких JSON-строк

Пример

$strings = ['valid', '{"key":123}', 'not json', '[]'];
foreach ($strings as $str) {
    $valid = function_exists('json_validate') ? json_validate($str) : (json_decode($str) !== null || json_last_error() === JSON_ERROR_NONE);
    echo "$str -> " . ($valid ? 'OK' : 'FAIL') . "\n";
}
valid -> FAIL
{"key":123} -> OK
not json -> FAIL
[] -> OK

10. Кодирование многомерного ассоциативного массива с индексированными подмассивами

Пример

$data = [
    'products' => [
        ['id' => 1, 'tags' => ['new', 'sale']],
        ['id' => 2, 'tags' => ['popular']]
    ],
    'meta' => ['count' => 2]
];
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
{
    "products": [
        {
            "id": 1,
            "tags": ["new", "sale"]
        },
        {
            "id": 2,
            "tags": ["popular"]
        }
    ],
    "meta": {
        "count": 2
    }
}

Эти примеры охватывают практические сценарии, с которыми сталкиваются разработчики при работе с JSON в PHP. Всегда полезно проверять версию PHP и доступные флаги, так как в новых версиях появляются дополнительные возможности (например, json_validate, JSON_THROW_ON_ERROR).

PHP: типы данных JSON - comments

En
Json types php (php)