Сериализация объектов и автозагрузка

Данный момент частично описан в официальной документации PHP, однако, на практике для большинства разработчиков он становится неприятной неожиданностью.

При сериализации объекта PHP сохраняет в итоговой строке имя класса и значения свойств объекта. Методы объекта и данные о родительских классах или имплементируемых интерфейсах не сохраняются. Следовательно, необходимый класс должен быть определён до того, как объект будет обратно десериализован из строки. В большинстве случаев все классы системы не имеет смысла подключать при каждом запросе. А если класс с нужным именем не был определён, PHP инстанцирует объект класса __PHP_Incomplete_Class_Name и определяет в нём свойства, сохранённые при сериализации объекта. Само собой, нормальная работа с таким объектом невозможна.

Положение исправляет автозагрузка классов, но одного наличия определённой функции __autoload() недостаточно, чтобы интерпретатор попытался автоматически подключить нужный класс. Для этого должна быть установлена директива конфигурации unserialize_callback_func, в которой указывается имя метода автозагрузки. Устанавливать значение этой директивы можно в любом месте, поэтому самое простое и правильное — на этапе инициализации приложения присвоить этой директиве значение __autoload. При этом нужно помнить, что если функция автозагрузки указана, но не определена, при вызове функции unserialize() возникнет warning.

Проблема становится ещё актуальнее, если вспомнить, что сессии для хранения данных используют именно сериализацию. Десериализация производится при вызове функции session_start(), которая часто вызывается в самом начале работы приложения. Ещё хуже, если сессия стартует автоматически (с использованием директивы session.auto_start(). В этом случае не помогает и использование директивы auto_prepend_file, то есть нет возможности стандартными средствами определить функцию автозагрузки до старта сессии.

В конечном итоге получается, что для нормального сохранения объектов в сессии нужно обязательное выполнение следующих условий:

  1. Автоматический запуск сессий отключён.
  2. Функция __autoload() определяется до момента старта сессии.
  3. До момента старта сессии выполняется команда ini_set('unserialize_callback_func', '__autoload').

Установку директивы unserialize_callback_func лучше размещать сразу после определения функции автозагрузки, чтобы сгруппировать эти важные элементы вместе.

Записи