Avatar ·

Сериализация массивов PHP: json_encode vs serialize — что выбрать?

Всем привет! Я новичок в PHP и столкнулся с дилеммой при разработке одного проекта. Мне нужно сохранять массивы в кэш (файлы или Redis), а потом читать их обратно. Я нашел два способа: serialize() и json_encode(). Но не могу понять, какой из них лучше использовать. Вот пример моего кода: ```php // Вариант 1: serialize $data = ['user' => 'Иван', 'age' => 30, 'hobbies' => ['чтение', 'программирование']]; $serialized = serialize($data); file_put_contents('cache.txt', $serialized); $restored = unserialize(file_get_contents('cache.txt')); // Вариант 2: json_encode $json = json_encode($data, JSON_UNESCAPED_UNICODE); file_put_contents('cache.json', $json); $decoded = json_decode(file_get_contents('cache.json'), true); ``` Оба варианта вроде работают, но я заметил странности: 1. serialize() создает более "грязную" строку с какими-то буквами и числами. 2. json_encode() выдает чистый JSON, который можно открыть в любом редакторе. 3. При работе с русскими символами json_encode без флага JSON_UNESCAPED_UNICODE превращает их в \uXXXX. Еще я слышал, что serialize() может быть опасен из-за инъекций, а json_encode быстрее. Но в некоторых форумах пишут обратное. Подскажите, пожалуйста, какой метод предпочтительнее для хранения массивов в PHP? Может есть какие-то подводные камни, о которых нужно знать новичку? Заранее спасибо за помощь! <<>>

Основные различия между serialize() и json_encode()

Вы затронули очень важную тему. Оба метода предназначены для преобразования PHP-данных в строку, но имеют принципиальные различия в назначении и поведении.

Когда использовать serialize()

serialize() — это родной PHP-формат для сохранения объектов и сложных типов данных. Он сохраняет:

  • Типы данных (integer, float, boolean, null, array, object)
  • Ссылки на объекты и циклические ссылки
  • Свойства private/protected классов
  • Ресурсы (например, соединения с БД — но это редкость)

Пример с объектом:

class User {
    private $name;
    protected $email;
    public $age;

    public function __construct($name, $email, $age) {
        $this->name = $name;
        $this->email = $email;
        $this->age = $age;
    }
}

$user = new User('Иван', 'ivan@test.ru', 30);
echo serialize($user);
// Вывод: O:4:"User":3:{s:11:"\0User\0name";s:8:"Иван";s:12:"\0*\0email";s:13:"ivan@test.ru";s:3:"age";i:30;}

Плюсы serialize():

  • Сохраняет всю структуру объекта, включая модификаторы доступа
  • Поддерживает сложные типы (например, SplObjectStorage)
  • Безопаснее для данных с бинарными значениями

Минусы serialize():

  • Формат непонятен другим языкам программирования
  • Потенциальная уязвимость: unserialize() может выполнить произвольный код при работе с недоверенными данными
  • Строка получается более объемной

Когда использовать json_encode()

json_encode() преобразует данные в универсальный формат JSON. Он идеален для:

  • Взаимодействия с JavaScript и REST API
  • Хранения в NoSQL базах данных (MongoDB, Redis)
  • Конфигурационных файлов
  • Логирования

Пример с многомерным массивом:

$data = [
    'users' => [
        ['name' => 'Иван', 'age' => 30],
        ['name' => 'Мария', 'age' => 25]
    ],
    'settings' => [
        'debug' => true,
        'max_items' => 100
    ]
];

$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
// Вывод: читаемый JSON с отступами
// {
//     "users": [
//         {"name": "Иван", "age": 30},
//         {"name": "Мария", "age": 25}
//     ],
//     "settings": {
//         "debug": true,
//         "max_items": 100
//     }
// }

Плюсы json_encode():

  • Человекочитаемый формат
  • Поддерживается всеми современными языками
  • Безопаснее: json_decode() не выполняет код
  • Обычно быстрее для простых массивов

Минусы json_encode():

  • Не сохраняет типы PHP (все целые числа могут стать float при декодировании)
  • Не работает с объектами (только с public свойствами)
  • Не поддерживает циклические ссылки
  • Проблемы с очень большими целыми числами (теряется точность)

Сравнение производительности

Проведите простой тест:

$testData = range(1, 10000);
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
    serialize($testData);
}
echo "serialize: " . (microtime(true) - $start) . " сек\n";

$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
    json_encode($testData);
}
echo "json_encode: " . (microtime(true) - $start) . " сек\n";

Для простых массивов json_encode() обычно на 20-50% быстрее. Но для объектов с private свойствами serialize() может быть быстрее, так как не нужно анализировать структуру.

Рекомендация

Для вашей задачи (кэширование массивов) используйте json_encode() с флагом JSON_UNESCAPED_UNICODE и JSON_THROW_ON_ERROR. Это безопаснее, быстрее и совместимее. Если понадобится сохранять объекты — используйте serialize(), но только для внутреннего использования.

<<>>

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

Если производительность критична, рассмотрите специализированные расширения PHP:

  • igbinary — формат сериализации, который быстрее serialize() и создает меньший размер данных. Поддерживается встроенными функциями igbinary_serialize() и igbinary_unserialize(). Отлично подходит для кэширования в Redis/Memcached.
  • msgpack — бинарный формат, похожий на JSON, но компактнее. Использует msgpack_pack() и msgpack_unpack(). Совместим с другими языками.

Пример с igbinary:

$data = ['key' => 'value', 'nested' => [1, 2, 3]];
$packed = igbinary_serialize($data);  // компактная бинарная строка
$restored = igbinary_unserialize($packed);
// Размер: ~30 байт против ~45 у serialize и ~35 у json_encode

Важно: Эти расширения нужно устанавливать отдельно через pecl или composer. Они не входят в стандартную поставку PHP. Для большинства проектов достаточно json_encode() или serialize(), но при высоких нагрузках igbinary может дать прирост производительности до 30-50%.

Еще один вариант — использовать var_export() для создания PHP-кода, который можно включить через require. Это удобно для конфигов, но не подходит для динамических данных из-за проблем с производительностью и безопасностью.