Обновить

Лучше не сохраняйте в сессии PHP объекты с защищенными или приватными свойствами, если сама сессия хранится в БД.

Оговорюсь, что не поддерживаю сохранение объектов в сессиях PHP, а пример взят из Legacy-проекта, в котором компонент рекомендованных продаж клиенту реализован в виде класса. Видимо предыдущие разработчики посчитали удобным не париться с сохранением рекомендаций в виде отдельной структуры, а сохраняли класс прямо в сессию клиента. Сами сессии хранятся в БД MySQL (тоже тема для отдельной дискуссии).

Всё это отлично работало до переезда БД на кодировку utf8mb4_general_ci. После чего начались плавающие ошибки: некоторых пользователей стало выкидывать из ПУ. Довольно быстро определили, что проблема с сессиями, чуть больше времени потребовалось, чтобы определить, что некоторые сессии внезапно становились битыми у тех клиентов, для которых срабатывал сервис подбора рекомендаций.

Немного теории. Оказалось, что PHP сохраняет свойства объектов в сессии с определенными особенностями:

  • публичные свойства `public $item` сохраняются как item

  • защищенные свойства `protected $item` сохраняются как \0*\0item

  • приватные свойства `private $item` сохраняются как \0ClassName\0item

причем \0 это нулевой байт. Главной проблемой стало то, что MySQL воспринимал этот нулевой байт как конец строки и сохранял в таблицу обрезанную строку. Сессия становилась невалидной.

Самое простое решение в данном случае изменить тип поля на BLOB, в этом случае текст корректно сохранится побайтово. По поводу вопроса, стоит ли сохранять объекты в сессию пользователя, каждый думаю решит для себя сам.

Теги:
+4
Комментарии0

Публикации