PHP: хранение «объектов» внутри $ _SESSION - PullRequest
181 голосов
/ 25 сентября 2008

Я только что понял, что могу на самом деле хранить объекты в $ _SESSION , и я нахожу это довольно круто, потому что когда я перехожу на другую страницу, у меня все еще есть мой объект. Теперь, прежде чем я начну использовать этот подход, я хотел бы выяснить, действительно ли это хорошая идея или есть потенциальные ловушки .

Я знаю, что если бы у меня была единственная точка входа, мне не нужно было бы этого делать, но я еще не там, поэтому у меня нет единой точки входа, и я действительно хотел бы сохранить свой объект, потому что Я не теряю свое состояние таким образом. (Теперь я также читал, что мне следует программировать сайты без сохранения состояния, но я пока не понимаю эту концепцию.)

Итак, , кратко : нормально ли хранить объекты в сеансе, есть ли проблемы с ним?


Edit:

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

Дальнейшие ответы могут быть более подробно об этом аспекте чуть больше!

Ответы [ 8 ]

129 голосов
/ 05 февраля 2012

Я знаю, что эта тема старая, но эта проблема продолжает появляться и не была обращена к моему удовлетворению:

Независимо от того, сохраняете ли вы объекты в $ _SESSION, или восстанавливаете их целиком на основе данных, хранящихся в скрытых полях формы, или повторно запрашиваете их из БД каждый раз, вы используете состояние. HTTP не имеет состояния (более или менее; но смотрите GET vs. PUT), но почти все, что кто-либо заботится о веб-приложении, требует сохранения состояния где-то. Действовать так, как будто толкать государство в укромные уголки равносильно некоторой теоретической победе, просто неправильно. Государство есть государство. Если вы используете состояние, вы теряете различные технические преимущества, получаемые при отсутствии состояния. Это не то, чтобы потерять сон, если вы заранее не знаете, что вам следует потерять сон из-за него.

Меня особенно сбивает с толку благословение, полученное в результате аргументов "двойного удара", выдвинутых Хэнком Гаем. Создает ли ОП распределенную систему электронной коммерции с балансировкой нагрузки? Мое предположение нет; и я буду далее утверждать, что сериализация его класса $ User, или что-то еще, не повредит его серверу без возможности восстановления. Мой совет: используйте методы, которые подходят для вашего приложения. С объектами в $ _SESSION все в порядке, если соблюдать меры предосторожности. Если ваше приложение вдруг превратится во что-то конкурирующее с Amazon по трафику, вам нужно будет заново адаптировать его. Это жизнь.

111 голосов
/ 25 сентября 2008

все в порядке, пока к моменту вызова session_start () объявление / определение класса уже встречалось в PHP или может быть найдено уже установленным автозагрузчиком. в противном случае он не сможет десериализовать объект из хранилища сеансов.

35 голосов
/ 25 сентября 2008

HTTP является протоколом без сохранения состояния по причине. Сеансы сваривают состояние на HTTP. Как правило, избегайте использования состояния сеанса.

UPDATE: На уровне HTTP нет понятия сеанса; серверы предоставляют это, предоставляя клиенту уникальный идентификатор и сообщая ему о необходимости повторной отправки при каждом запросе. Затем сервер использует этот идентификатор в качестве ключа в большой хэш-таблице объектов Session. Всякий раз, когда сервер получает запрос, он ищет информацию о сеансе в своей хэш-таблице объектов сеанса на основе идентификатора, предоставленного клиентом вместе с запросом. Вся эта дополнительная работа - двойной удар по масштабируемости (большая причина, по которой HTTP не сохраняет состояния).

  • Whammy One: уменьшает работу, которую может выполнять один сервер.
  • Whammy Two: его масштабировать становится сложнее, потому что теперь вы не можете просто перенаправить запрос на любой старый сервер - у них не все имеют одинаковый сеанс. Вы можете закрепить все запросы с данным идентификатором сеанса на одном сервере. Это не легко, и это единственная точка отказа (не для системы в целом, а для больших групп ваших пользователей). Или же вы можете совместно использовать хранилище сеансов для всех серверов в кластере, но теперь у вас больше сложностей: подключенная к сети память, автономный сервер сеансов и т. Д.

Учитывая все это, чем больше информации вы добавляете в сеанс, тем больше влияние на производительность (как указывает Винко). Также, как указывает Винко, если ваш объект не сериализуем, сеанс будет вести себя неправильно. Так что, как правило, избегайте внесения в сессию большего, чем необходимо.

@ Vinko Обычно вы можете обойти состояние хранилища сервера, внедрив данные, которые вы отслеживаете, в ответ, который вы отправляете обратно, и попросив клиента отправить его повторно, например, отправив данные в скрытый вход. Если вам действительно нужно отслеживание состояния на стороне сервера, вероятно, оно должно быть в вашем резервном хранилище данных.

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

18 голосов
/ 25 сентября 2008
  • Объекты, которые нельзя сериализовать (или которые содержат не сериализуемые элементы), не будут выходить из $ _SESSION, как вы ожидаете
  • Огромные сеансы обременяют сервер (сериализация и десериализация мегабайт состояния каждый раз обходятся дорого)

Кроме этого я не видел проблем.

9 голосов
/ 25 сентября 2008

По моему опыту, обычно это не стоит того, что сложнее, чем StdClass с некоторыми свойствами. Стоимость десериализации всегда была больше, чем воссоздание из базы данных с сохраненным в сеансе идентификатором. Это кажется классным, но (как всегда), профилирование - это ключ.

6 голосов
/ 25 сентября 2008

Я бы посоветовал не использовать состояние, если оно вам абсолютно не нужно. Если вы можете перестроить объект без использования сессий, сделайте это. Наличие состояний в вашем веб-приложении делает приложение более сложным для построения, для каждого запроса вы должны видеть, в каком состоянии находится пользователь. Конечно, бывают случаи, когда вы не можете избежать использования сеанса (пример: пользователь должен оставаться в системе во время сеанса на веб-приложение). В заключение я хотел бы предложить, чтобы ваш объект сеанса был как можно меньшим, так как это влияет на производительность для сериализации и десериализации больших объектов.

4 голосов
/ 25 сентября 2008

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

Также учитывайте размер сеанса, в зависимости от того, как он хранится, у вас могут быть ограничения по размеру или проблемы с задержкой.

0 голосов
/ 11 февраля 2016

Я также упоминал бы при обновлении библиотек программного обеспечения - мы обновили наше программное обеспечение, и у старой версии были объекты в сеансе с именами классов программного обеспечения V1, новое программное обеспечение зависало при попытке построить объекты, которые были в сеансе - поскольку программное обеспечение V2 больше не использовало те же классы, оно не могло их найти. Нам пришлось вставить некоторый код исправления, чтобы обнаружить объекты сеанса, удалить сеанс, если он найден, перезагрузить страницу. Изначально самой большой болью было то, что вы воссоздали эту ошибку, когда о ней впервые сообщили (слишком знакомо, «ну, это работает для меня» :), поскольку это затрагивало только людей, которые недавно использовали старые и новые системы - однако, хорошо Работа, которую мы нашли перед запуском, поскольку все наши пользователи наверняка имели бы старые переменные сеанса в своих сеансах и потенциально могли бы потерпеть крах для всех, это был бы ужасный запуск:)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...