Обновить
4K+
2

Пользователь

-0,5
Рейтинг
Отправить сообщение

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

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

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

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

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

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

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

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

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

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

Функция date меняет поведение в PHP 8.x

При переносе Legacy-проекта с PHP 7.4 на 8.4 столкнулся с недокументированной проблемой изменения поведения функции date при передаче в качестве параметра timestamp значения NULL Один и тот же код даст разный результат:

echo date("Y-m-d H:i:s", null);

// PHP 7.4 и ниже 1970-01-01 00:00:00

// PHP 8.0 и выше 2026-01-14 08:11:56

В примере NULL передается в явном виде, но в рабочем коде он вполне может прилетать из БД или других переменных, поэтому потенциальная ошибка может остаться незамеченной. Вообще, по принципам ООП, явное всегда лучше неявного, да и сам я сторонник использования \DateTime. В этом случае, результат кода:

$date = new \DateTime();
$date->setTimestamp(null);
echo $date->format("Y-m-d H:i:s");

был бы одинаковый, а с версии 8.1 вы бы начали получать предупреждение

Deprecated: DateTime::setTimestamp(): Passing null to parameter #1 ($timestamp) 
of type int is deprecated
1970-01-01 00:00:00

Я бы рекомендовал перед миграцией версий PHP в Legacy-проектах либо учитывать эту особенность поведения функции date и убедиться, что NULL не приходит в параметр timestamp, либо сразу сделать рефакторинг на \DateTime, чтобы в принципе избежать таких проблем.

Теги:
Всего голосов 6: ↑6 и ↓0+6
Комментарии0

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность