PHP: Зберігання "об'єктів" всередині $ _SESSION


188

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

Я знаю, що якби у мене був єдиний пункт входу, мені не потрібно було б цього робити, але я ще не там, тому я не маю єдиної точки входу, і я дуже хотів би зберегти свій об'єкт, бо я цього не роблю ' не втрачаю такого стану. (Зараз я також читав, що я повинен програмувати сайти без громадянства, але ще не розумію цієї концепції.)

Отже, коротко : чи нормально зберігати об’єкти в сеансі, чи є з цим проблеми?


Редагувати:

Тимчасовий підсумок : На сьогоднішній день я розумію, що, мабуть, краще відтворити об’єкт, навіть якщо це вимагає повторного запиту бази даних.

Подальші відповіді, можливо, можуть детальніше пояснити цей аспект !


13
Яким "дурним" я був у 2008 році :-)
markus

49
але корисне запитання до «дурних, як ми у 2014 році: D
Момін Аль Азіз

3
Дуже приємні запитання, які ви задали markus .. :) Я це прочитав сьогодні;)
gkd

1
Ви не були дурні! Ви запитували, про що я збирався запитати, і зробили мене суцільним через 10 років!
Тоддмо

ну, я здогадався, ти щойно врятував мене від
Максвелл

Відповіді:


133

Я знаю, що ця тема є давньою, але це питання постійно виникає, і я не був вирішений на моє задоволення

Незалежно від того, чи зберігаєте ви об’єкти в $ _SESSION, або реконструюєте їх цілою тканиною на основі даних, що зберігаються в полях прихованої форми, або повторно запитуєте їх у БД кожен раз, ви використовуєте стан. HTTP не має статусу (більше чи менше; але дивіться GET vs. PUT), але майже все, що хто завгодно робить із веб-додатком, вимагає, щоб стан десь підтримувався. Діяти так, ніби підштовхування держави до куточків - це певна теоретична перемога - просто неправильно. Держава - держава. Якщо ви використовуєте штат, ви втрачаєте різні технічні переваги, здобуті без громадянства. Це не те, що втрачати сон, якщо ви не знаєте заздалегідь, що вам слід втрачати сон через це.

Мене особливо вражає благословення, отримане аргументами "подвійного свавілля", викладеним Генком Гей. Чи побудова ОП - це розподілена та збалансована навантаження система електронної комерції? Моя здогадка - ні; і я продовжую стверджувати, що серіалізація його класу $ User, або що завгодно, не покалічить його сервер після ремонту. Моя порада: використовуйте прийоми, зрозумілі для вашої програми. Об'єкти в $ _SESSION добре, з дотриманням здорових застережень. Якщо ваш додаток раптом перетвориться на щось, що конкурує з Амазонкою в обслуговуваному трафіку, вам доведеться повторно адаптуватися. Це життя.


16
Хороша відповідь, що містить багато моїх власних думок, коли я читав це. Сучасний Інтернет потребує держави. Хоча деякі програми не потребують стану та має сенс робити це без громадянства, сучасний Інтернет покладається на занадто багато систем, що базуються на стані (AKA: Логіни!), Щоб просто відмовитися від них! Великі боги Інтернету впродовж багатьох років навіть включили цю базову концепцію у вигляді файлів cookie, і на базовому рівні вони додали її у вигляді локального сховища в HTML. Можливо, має сенс уникати надмірного використання стану в деяких додатках, але в деяких! = У всіх!
RonLugge

Що ж, коли я задав це питання незабаром після того, як людина винайшла вогонь, я не знала багато речей, які я знаю сьогодні ... що так само добре. Тим часом я можу сказати, що може бути кілька корисних випадків, але, як правило, спершу я шукаю інші рішення. Все-таки це позначається як нова прийнята відповідь, оскільки інша відповідь - категорична.
markus

Дуже мало відповідей змушують мене сміятися вголос. Цей і зробив. Браво +1
тоддмо

114

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


12
Дякую! Це вирішило для мене помилку: D
Метт Еллен

Я припускаю, що цієї проблеми можна було б уникнути, якщо у вас є належна __autoload()функція.
Лангел

Несеріалізуючи серіалізований об'єкт, чи потрібно додати визначення класу ??? На момент серіалізації об'єкта йому потрібно визначення класу, що я згоден, але чи потрібно додати визначення класу також у файл, де мені доведеться несериалізувати серіалізований об'єкт ???
Rajesh Paul

35

HTTP - це протокол без громадянства. Сеанси зварюють стан на HTTP. Як правило, уникайте використання стану сеансу.

ОНОВЛЕННЯ: Не існує концепції сеансу на рівні HTTP; сервери надають це, надаючи клієнтові унікальний ідентифікатор і кажучи клієнту повторно подати його на кожен запит. Тоді сервер використовує цей ідентифікатор як ключ до великого хештелю об'єктів Session. Кожного разу, коли сервер отримує запит, він шукає інформацію про сеанс з його хеш-пам’яті об’єктів сеансу на основі ідентифікатора, який клієнт подав із запитом. Вся ця додаткова робота - це подвійна розвага щодо масштабованості (велика причина, що HTTP без громадянства).

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

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

@Vinko Зазвичай ви можете обійти стан зберігання сервера, вставивши дані, які ви відстежуєте, у відповідь, яку ви надсилаєте назад, і змусивши клієнта повторно подати їх, наприклад, надсилаючи дані в прихованому вході. Якщо вам дійсно потрібно відстеження стану на сервері, воно, ймовірно, повинно бути у вашому резервному сховищі даних.

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


1
Не існує концепції сеансу на рівні HTTP; сервери надають це, надаючи клієнтові унікальний ідентифікатор і кажучи клієнту повторно подати його на кожен запит. Тоді сервер використовує цей ідентифікатор як ключ до великого хештелю об'єктів Session. Продовження…
Хенк Гей,

1
Кожного разу, коли сервер отримує запит, він шукає інформацію про сеанс з його хеш-пам’яті об’єктів сеансу на основі ідентифікатора, який клієнт подав із запитом. Вся ця додаткова робота - це подвійна розвага щодо масштабованості (велика причина, що HTTP без громадянства). Продовження…
Хенк Гей,

1
Цікаво, як би ви якось реалізували складні програми через HTTP, не
зварюючи

3
будь ласка, відредагуйте свою відповідь, щоб включити всі ці коментарі. легше читати і краще для вікі, і все одно я не можу обрати вашу відповідь як прийняту, якщо все важливе - у коментарях. Дякую!
Маркус

6
Я б хотів, щоб я спростував це ще більше. Знай свій термін. Посилання на пам'ять коштує 100 наносекунд або 0,0001 мс. Отже, пошук на хештелі, який зберігається в основній пам'яті, буквально не витрачає часу. Є чи O(1)сказати вам що - небудь? @whammy два: просто не випадково направляйте всі запити на випадкові сервери? виконувати кругообіг та продовжувати маршрутизацію до того ж сервера від одного користувача. Це вау, супер очевидно. Ви повинні повернутися до своїх книг разом із усіма оновленнями 30+
Toskan

19
  • Об'єкти, які не можуть бути серіалізовані (або які містять несеріалізаційних членів), не вийдуть з $ _SESSION, як ви очікували
  • Величезні сеанси накладають тягар на сервер (серіалізація та десериалізація державних мег щоразу коштує дорого)

Крім цього я не бачив жодних проблем.


9

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


Будь-який коментар щодо ефективності між запитом таблиці 5x2 даних при кожному запиті проти кешування результату в сеансі та використанням цього?
musicliftsme

6

Я б запропонував не використовувати стан, якщо вам це абсолютно не потрібно. Якщо ви можете відновити об'єкт без використання сеансів, зробіть це. Наявність станів у вашій веб-застосуванні робить додаток складнішим для створення, для кожного запиту ви повинні бачити, у якому стані знаходиться користувач. Звичайно, є випадки, коли ви не можете уникнути використання сеансу (наприклад: користувачеві потрібно зберігати вхід під час його сеансу на webapplication). Останнє, я б запропонував зберегти ваш об'єкт сеансу якомога меншим, оскільки це вплине на продуктивність для серіалізації та несеріалізації великих об’єктів.


Отже, чи краще відновити об’єкт, включаючи виконання всіх запитів до бази даних знову? Тому що однією з моїх думок для цього було те, що мені більше не потрібно запитувати db на ті самі речі.
Маркус

3
Якщо вам важливо, що вона не запитуватиме базу даних, використовуйте кешування замість того, щоб зберігати її в сеансі. Але будь-ласка, перш ніж робити щось на кшталт створення кешування, перевірте, чи це дійсно хіт продуктивності.
Джонні

Дякую, я насправді думаю, що це не так. Я просто повинен запитати ще раз.
Маркус

4

Вам доведеться пам’ятати, що типи ресурсів (наприклад, db-з'єднання або покажчики файлів) не зберігатимуться між завантаженнями сторінок, і вам потрібно буде невидимо їх знову створити.

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


0

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

У будь-якому випадку, як ви пропонуєте у своїй поправці, я також думаю, що краще створити об'єкт заново. Тому, можливо, просто зберігати ідентифікатор, а потім на кожен запит, який витягує об'єкт із бази даних, краще / безпечніше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.