PHP: хранение «объектов» внутри $ _SESSION

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

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

Итак, Суммируя: Можно ли хранить объекты в сеансе, есть ли с этим проблемы?


Редактировать:

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

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

Каким «глупым» я был в 2008 году :-)

markus 08.12.2013 18:59

но полезный вопрос к таким глупцам, как мы в 2014 году: D

Gun2sh 03.01.2014 01:32

Очень хорошие вопросы, которые вы задали Маркусу .. :) Я прочитал это сегодня;)

Shyam 27.06.2014 11:29

Ты не был дураком! Вы спросили, о чем я собирался спросить, и сделали мне твердый ответ 10 лет спустя!

toddmo 27.03.2018 21:21

ну я догадался, что вы только что спасли меня от глупого вопроса в 2019 году

Maxwell 27.03.2019 14:54

Чтобы добавить к этому - я столкнулся со ВСЕМИ ВИДАМИ странных проблем с PHP 7.1, сохраняющим мой полный объект $ user в сеансе ... в конце концов, было легко просто отслеживать идентификатор пользователя и воссоздавать объект при загрузке страницы. .. и бум все мои баги исчезли.

Eric 13.07.2019 19:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
190
6
98 034
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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

Спасибо! Это исправило ошибку для меня: D

Matt Ellen 12.03.2010 17:55

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

Langel 19.06.2013 00:02

При десериализации сериализованного объекта мы должны добавить определение класса ??? Во время сериализации объекта ему требуется определение класса, с чем я согласен, но должен ли я добавить определение класса также в файл, где я должен десериализовать сериализованный объект ???

Rajesh Paul 20.09.2013 23:08

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

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

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

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

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

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

сварить? что ты имеешь в виду? Можете ли вы объяснить свою точку зрения более подробно, и почему это практическое правило?

markus 25.09.2008 12:56

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

Hank Gay 25.09.2008 13:00

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

Hank Gay 25.09.2008 13:03

Интересно, как бы вы реализовали сложные приложения через HTTP без состояния сварки?

Vinko Vrsalovic 25.09.2008 13:04

Whammy One: сокращает объем работы, которую может выполнять один сервер. Whammy Two: это затрудняет масштабирование, потому что теперь вы не можете просто направить запрос на любой старый сервер - у них не у всех одинаковый сеанс. Продолжение следует…

Hank Gay 25.09.2008 13:05

Вы можете закрепить все запросы с данным идентификатором сеанса на одном сервере. Это непросто, и это единственная точка отказа. Или вы можете совместно использовать хранилище сеанса на всех серверах в кластере, но теперь у вас есть более сложная задача: подключенная к сети память, автономный сервер сеанса и т. д. TBC ...

Hank Gay 25.09.2008 13:06

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

Hank Gay 25.09.2008 13:09

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

Hank Gay 25.09.2008 13:11

отредактируйте свой ответ, включив в него все эти комментарии. его легче читать и лучше для вики, и в любом случае я не могу выбрать ваш ответ как принятый, если все важное находится в комментариях. Благодарность!

markus 25.09.2008 13:13

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

John 28.06.2010 07:11

Ваше «резервное хранилище данных» (если вы не используете сеансы) и «память, подключенная к сети» (для хранения сеансов), могут легко быть одной и той же службой, например используя MySQL в качестве хранилища сеансов. В этом случае для использования сессий нет недостатков.

thenickdude 13.01.2012 12:15

"whammy one" Хотел бы я проголосовать против этого больше. Знайте свое время. Обращение к памяти стоит 100 наносекунд или 0,0001 мс. Таким образом, поиск в хеш-таблице, которая хранится в основной памяти, буквально не требует затрат времени. O(1) вам что-то говорит? @whammy two: просто не перенаправлять все запросы случайным образом на случайные серверы? выполнить циклический перебор и продолжить маршрутизацию на тот же сервер от одного и того же пользователя. Это вау, супер очевидно. Вы должны вернуться к своим книгам вместе со всеми 30+ голосами за

Toskan 14.06.2014 04:53

"Whammy Two" отменяется, если вы сохраняете сеансы в базе данных. В PHP есть метод, который делает это чрезвычайно простым (session_set_save_handler ()).

Jabari 10.02.2015 01:58

@Toskan "whammy one" не о процессоре, а о памяти. Люди неизбежно получают на сеансе много больше материала, чем они думают; это так просто. С точки зрения ЦП / времени единственная «медленная» вещь в версии сеанса на основе хеш-таблицы - это когда он должен расти: как только он станет достаточно большим, может возникнуть проблема внезапного выделения такого гигантского фрагмента непрерывной памяти. (потому что у вас может быть не так много, и вдруг сборщик мусора / среда выполнения должна переставить «свободные» страницы, компактный мусор и т. д.).

Hank Gay 10.02.2015 17:28

@HankGay, где я сказал, что это про процессор? Что-то, что не принадлежит сеансу, не принадлежит ему, да.

Toskan 12.02.2015 06:43

@Toskan По моему опыту, единственный способ не допустить «чего-то, что не принадлежит сеансу» - это предположить, что ничто не принадлежит сеансу, пока вы не убедите остальную команду, что это так. Даже в этом случае рекомендуется вернуться и просмотреть, потому что кто-то может случайно добавить свойство (потенциально интенсивно использующее память) к какому-либо объекту, который сериализуется в сеанс каким-либо другим фрагментом кода, и внезапно вы ' нам приходится запускать больше серверов из-за какой-то загадочной «утечки памяти». Я не возражаю, что у сеанса есть свои применения; Я просто считаю, что им злоупотребляют.

Hank Gay 12.02.2015 22:20

Предупреждение для всех, кто прислушивается к этому совету: да, с помощью PHP легко хранить данные сеанса в базе данных, но будьте осторожны с производительностью на загруженных серверах. Если вы выполняете более пары десятков запросов в секунду, вы увидите значительное снижение производительности. Система сеансов на основе файлов по умолчанию намного быстрее, чем база данных. Если вам нужно масштабировать несколько серверов, вы всегда можете сегментировать данные и назначить каждого пользователя определенному серверу, чтобы они никогда не теряли сеанс.

Vincent 09.07.2019 02:20
  • Объекты, которые не могут быть сериализованы (или которые содержат несериализуемые члены), не будут выходить из $ _SESSION, как и следовало ожидать.
  • Огромные сеансы создают нагрузку на сервер (сериализация и десериализация мегабайт состояния каждый раз стоит дорого)

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

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

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

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

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

markus 25.09.2008 13:05

Если для вас важно, чтобы он больше не запрашивал базу данных, используйте кеширование вместо сохранения в сеансе. Но, пожалуйста, прежде чем делать что-либо вроде кэширования, проверьте, действительно ли это снижает производительность.

Johnny 25.09.2008 13:46

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

markus 25.09.2008 14:00

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

Любые комментарии по производительности между запросом таблицы данных 5x2 при каждом запросе и кешированием результата в сеансе и его использованием?

musicliftsme 08.12.2015 23:32
Ответ принят как подходящий

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

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

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

Хороший ответ, включающий в себя множество моих собственных мыслей, пока я читал это. Современное состояние Интернета потребности. В то время как некоторым приложениям не требуется состояние и имеет смысл создавать без отслеживания состояния, современный Интернет полагается на слишком много систем, основанных на состоянии (также известные как логины!), Чтобы просто отказаться от них! Великие боги Интернета в течение многих лет даже включали эту базовую концепцию в виде файлов cookie, а на базовом уровне они добавили ее в виде локального хранилища в HTML. Возможно, имеет смысл избегать чрезмерного использования состояния в приложениях немного, но некоторые! = Все!

RonLugge 29.03.2012 10:28

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

markus 18.02.2013 01:58

Очень немногие ответы заставляют меня смеяться вслух. Этот сделал. Браво +1

toddmo 27.03.2018 21:21

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

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

Другие вопросы по теме