PHP: Przechowywanie „obiektów” wewnątrz $ _SESSION

188

Właśnie zorientowałem się, że faktycznie mogę przechowywać obiekty w $ _SESSION i uważam, że jest całkiem fajny, ponieważ kiedy przeskakuję na inną stronę, wciąż mam swój obiekt. Zanim zacznę stosować to podejście, chciałbym dowiedzieć się, czy to naprawdę tak dobry pomysł, czy też wiąże się to z potencjalnymi pułapkami .

Wiem, że gdybym miał jeden punkt wejścia, nie musiałbym tego robić, ale jeszcze go tam nie ma, więc nie mam ani jednego punktu wejścia i naprawdę chciałbym zatrzymać swój obiekt, ponieważ nie Tak stracę swój stan. (Teraz też przeczytałem, że powinienem programować witryny bezstanowe, ale nie rozumiem jeszcze tego pojęcia).

Więc w skrócie : Czy to jest ok do przechowywania obiektów w sesji, czy są jakieś problemy z tym?


Edytować:

Podsumowanie tymczasowe : do tej pory rozumiem, że prawdopodobnie lepiej jest odtworzyć obiekt, nawet jeśli wymaga to ponownego zapytania do bazy danych.

Dalsze odpowiedzi mogą nieco bardziej rozwinąć ten aspekt !

markus
źródło
13
Jak „głupia” byłam w 2008 roku :-)
markus
49
ale przydatne pytanie do „głupich takich jak my w 2014 roku: D
Momin Al Aziz
3
Bardzo fajne pytania, które zadałeś markus .. :) Przeczytałem to dzisiaj;)
gkd
1
Nie byłeś głupi! Zapytałeś o to, o co chciałem zapytać, i zrobiłeś mi solidne 10 lat później!
toddmo
Cóż, zgadłem, że właśnie uratowałeś mnie przed zadaniem głupiego pytania w 2019 r.
Maxwell

Odpowiedzi:

133

Wiem, że ten temat jest stary, ale ten problem wciąż się pojawia i nie został rozwiązany w sposób ku mojemu zadowoleniu:

Niezależnie od tego, czy zapisujesz obiekty w $ _SESSION, czy rekonstruujesz je w całości na podstawie danych ukrytych w ukrytych polach formularzy, czy też ponownie pytasz je z bazy danych za każdym razem, gdy używasz stanu. HTTP jest bezstanowy (mniej więcej; ale zobacz GET vs. PUT), ale prawie wszystko, co ktoś obchodzi z aplikacją internetową, wymaga gdzieś stanu. Zachowanie się tak, jakby pchanie państwa w zakamarki oznacza jakieś teoretyczne zwycięstwo, jest po prostu złe. Państwo jest stanem. Jeśli użyjesz stanu, stracisz różne techniczne korzyści uzyskane przez bycie bezpaństwowcem. To nie jest coś, na co można stracić sen, chyba że wiesz z góry, że powinieneś tracić sen.

Szczególnie podoba mi się błogosławieństwo otrzymane przez argumenty „podwójnego biczowania” Hanka Gaya. Czy PO tworzy rozproszony i zrównoważony system e-commerce? Domyślam się, że nie; i dalej zakładam, że serializacja jego klasy $ User, czy cokolwiek innego, nie spowoduje uszkodzenia jego serwera, którego nie da się naprawić. Moja rada: stosuj techniki, które są rozsądne dla twojej aplikacji. Obiekty w $ _SESSION są w porządku, pod warunkiem zachowania zdrowego rozsądku. Jeśli Twoja aplikacja nagle zmieni się w obsługiwaną przez Amazon usługę rywalizującą z Amazonem, musisz ją ponownie dostosować. To jest życie.

shanusmagnus
źródło
16
Ładna odpowiedź zawierająca wiele moich własnych myśli, które czytałam. Nowoczesny internet potrzebuje państwa. Podczas gdy niektóre aplikacje nie potrzebują stanu i mają sens, aby robić to w sposób bezstanowy, współczesny internet opiera się na zbyt wielu systemach opartych na stanie (AKA: Loginy!), Aby je po prostu zrezygnować! Wielcy bogowie internetu nawet od lat wprowadzili tę podstawową koncepcję w postaci plików cookie, a na podstawowym poziomie dodali ją w postaci lokalnego przechowywania w HTML. Rozsądne może być unikanie nadmiernego wykorzystywania stanu w niektórych aplikacjach, ale niektóre! = Wszystkie!
RonLugge
Cóż, kiedy zadałem to pytanie wkrótce po tym, jak człowiek wynalazł ogień, nie znałem wielu rzeczy, które znam dzisiaj ... co też jest dobre. Tymczasem powiedziałbym, że może być kilka dobrych przypadków użycia, ale ogólnie najpierw szukam innych rozwiązań. Nadal oznacza to jako nową zaakceptowaną odpowiedź, ponieważ druga odpowiedź jest kategoryczna.
markus
Bardzo niewiele odpowiedzi sprawia, że ​​się śmieję. Ten zrobił. Bravo +1
toddmo
114

jest OK, o ile do czasu wywołania session_start () deklaracja / definicja klasy została już napotkana przez PHP lub może zostać znaleziona przez już zainstalowany autoloader. w przeciwnym razie nie byłoby w stanie deserializować obiektu ze sklepu sesji.

Crizer
źródło
12
Dzięki! To naprawiło błąd: D
Matt Ellen
Zakładam, że tego problemu można uniknąć, jeśli masz odpowiednią __autoload()funkcję.
Langel
Czy przy odserializowaniu obiektu serializowanego musimy dodać definicję klasy? W momencie serializacji obiektu potrzebuje definicji klasy, którą zgadzam się, ale czy muszę dodać definicję klasy również do pliku, w którym muszę odserializować obiekt serializowany?
Rajesh Paul,
35

HTTP jest bez powodu protokołem bezstanowym. Sesje spawają stan na HTTP. Zasadniczo unikaj używania stanu sesji.

AKTUALIZACJA: Nie ma koncepcji sesji na poziomie HTTP; serwery zapewniają to, podając klientowi unikalny identyfikator i każąc mu przesłać go ponownie przy każdym żądaniu. Następnie serwer używa tego identyfikatora jako klucza do dużego zbioru skrótów obiektów sesji. Za każdym razem, gdy serwer otrzyma żądanie, wyszukuje informacje o sesji na podstawie tablicy obiektów sesji na podstawie identyfikatora przesłanego przez klienta z żądaniem. Cała ta dodatkowa praca to podwójny wpływ na skalowalność (duży powód, dla którego HTTP jest bezstanowy).

  • Whammy One: Zmniejsza pracę, jaką może wykonać pojedynczy serwer.
  • Whammy Two: utrudnia skalowanie, ponieważ teraz nie można po prostu skierować żądania do dowolnego starego serwera - nie wszystkie mają tę samą sesję. Możesz przypiąć wszystkie żądania o danym identyfikatorze sesji do tego samego serwera. To nie jest łatwe i jest to pojedynczy punkt awarii (nie dla całego systemu, ale dla dużych części użytkowników). Możesz też współużytkować pamięć sesji na wszystkich serwerach w klastrze, ale teraz masz większą złożoność: pamięć podłączoną do sieci, autonomiczny serwer sesji itp.

Biorąc to wszystko pod uwagę, im więcej informacji umieścisz w sesji, tym większy będzie wpływ na wydajność (jak zauważa Vinko). Również, jak zauważa Vinko, jeśli twój obiekt nie jest możliwy do serializacji, sesja będzie się źle zachowywać. Dlatego z zasady unikaj stawiania w sesji więcej niż absolutnie konieczne.

@ Vinko Zazwyczaj można obejść stan magazynu serwera, osadzając śledzone dane w odpowiedzi, którą odsyłasz i zlecając ponowne przesłanie przez klienta, np. Wysyłając dane w ukryty sposób. Jeśli naprawdę potrzebujesz śledzenia stanu po stronie serwera, prawdopodobnie powinien on znajdować się w magazynie danych kopii zapasowej.

(Vinko dodaje: PHP może używać bazy danych do przechowywania informacji o sesji, a ponowne przesłanie danych przez klienta za każdym razem może rozwiązać potencjalne problemy ze skalowalnością, ale otwiera dużą puszkę problemów związanych z bezpieczeństwem, na które należy teraz zwrócić uwagę, ponieważ klient kontroluje wszystkie Twój stan)

Hank Gay
źródło
1
Nie ma koncepcji sesji na poziomie HTTP; serwery zapewniają to, podając klientowi unikalny identyfikator i każąc mu przesłać go ponownie przy każdym żądaniu. Następnie serwer używa tego identyfikatora jako klucza do dużego zbioru skrótów obiektów sesji. Ciąg dalszy nastąpi…
Hank Gay
1
Za każdym razem, gdy serwer otrzyma żądanie, wyszukuje informacje o sesji na podstawie tablicy obiektów sesji na podstawie identyfikatora przesłanego przez klienta z żądaniem. Cała ta dodatkowa praca to podwójny wpływ na skalowalność (duży powód, dla którego HTTP jest bezstanowy). Ciąg dalszy nastąpi…
Hank Gay
1
Zastanawiam się, jak zaimplementowałbyś złożone aplikacje przez HTTP bez spawania, jakoś
Vinko Vrsalovic,
3
edytuj swoją odpowiedź, aby uwzględnić wszystkie te komentarze. dla wiki jest łatwiejsza do odczytania i lepiej, a poza tym nie mogę wybrać twojej odpowiedzi jako zaakceptowanej, jeśli wszystko ważne jest w komentarzach. dzięki!
markus
6
„whammy one” Chciałbym móc bardziej głosować za tym. Poznaj swój czas. Odwołanie do pamięci kosztuje 100 nano sekund lub 0,0001 ms. Dlatego wyszukiwanie tablicy mieszającej przechowywanej w pamięci głównej dosłownie nie kosztuje czasu. Czy O(1)ci coś powiedzieć? @whammy two: po prostu nie losowo kieruj wszystkich żądań do losowych serwerów? wykonaj round robin i kontynuuj routing do tego samego serwera od tego samego użytkownika. To łał, super oczywiste. Musisz wrócić do swoich książek i wszystkich ponad 30 pozytywnych opinii
Toskan
19
  • Obiekty, których nie można zserializować (lub które zawierają elementy nieserializowane) nie wyjdą z $ _SESSION, jak można się spodziewać
  • Ogromne sesje obciążają serwer (serializowanie i deserializowanie megabajtów stanu za każdym razem jest drogie)

Poza tym nie widziałem żadnych problemów.

Vinko Vrsalovic
źródło
9

Z mojego doświadczenia wynika, że ​​generalnie nie jest to warte niczego bardziej skomplikowanego niż StdClass z pewnymi właściwościami. Koszt odserializowania zawsze był wyższy niż odtworzenie z bazy danych, biorąc pod uwagę identyfikator przechowywany w sesji. To wydaje się fajne, ale (jak zawsze) profilowanie jest kluczem.

Greg
źródło
Czy jest jakiś komentarz na temat wydajności między odpytywaniem tabeli danych 5x2 przy każdym żądaniu a buforowaniem wyniku w sesji i korzystaniem z niego?
musicliftsme
6

Sugeruję nie używać stanu, chyba że jest to absolutnie potrzebne. Jeśli możesz odbudować obiekt bez użycia sesji, zrób to. Posiadanie stanów w aplikacji internetowej sprawia, że ​​aplikacja jest trudniejsza do zbudowania, przy każdym żądaniu musisz zobaczyć, w jakim stanie jest użytkownik. Oczywiście zdarzają się sytuacje, w których nie można uniknąć korzystania z sesji (na przykład: użytkownik musi być zalogowany podczas sesji na aplikacja internetowa). Na koniec sugeruję, aby obiekt sesji był jak najmniejszy, ponieważ wpływa to na wydajność w celu serializacji i odserializowania dużych obiektów.

Jasio
źródło
Czy więc lepiej jest odbudować obiekt, w tym ponownie wykonać wszystkie zapytania do bazy danych? Ponieważ jedną z moich myśli za zrobienie tego było to, że nie muszę ponownie pytać db o te same rzeczy.
markus
3
Jeśli jest dla Ciebie ważne, że nie będzie ponownie sprawdzać bazy danych, użyj buforowania zamiast przechowywania jej w sesji. Ale proszę, zanim zrobisz coś takiego jak budowanie pamięci podręcznej, sprawdź, czy to naprawdę hit wydajności.
Johnny,
Dzięki, myślę, że tak nie jest. Powinienem jeszcze raz zapytać.
markus
4

Musisz pamiętać, że typy zasobów (takie jak połączenia db lub wskaźniki plików) nie będą się utrzymywać między ładowaniami stron i będziesz musiał je w niewidoczny sposób odtworzyć.

Weź również pod uwagę rozmiar sesji, w zależności od sposobu jej przechowywania, mogą wystąpić ograniczenia rozmiaru lub problemy z opóźnieniami.

Marc Gear
źródło
0

Powiedziałbym również o aktualizacji bibliotek oprogramowania - zaktualizowaliśmy nasze oprogramowanie, a stara wersja miała obiekty w sesji z nazwami klas oprogramowania V1, nowe oprogramowanie ulegało awarii, gdy próbowało zbudować obiekty, które były w sesji - tak jak V2 oprogramowanie nie używało już tych samych klas, nie mogło ich znaleźć. Musieliśmy wprowadzić kod naprawczy, aby wykryć obiekty sesji, usunąć sesję, jeśli zostanie znaleziona, ponownie załadować stronę. Największy ból początkowo miał na myśli, że odtwarzałeś ten błąd, gdy został zgłoszony (aż nazbyt dobrze, „dobrze, działa dla mnie” :), ponieważ wpłynął on tylko na ludzi, którzy ostatnio wchodzili i wychodzili ze starych i nowych systemów - jednak dobry zadanie, które znaleźliśmy przed uruchomieniem, ponieważ wszyscy nasi użytkownicy z pewnością mieliby stare zmienne sesji w swoich sesjach i potencjalnie rozbili się dla wszystkich,

W każdym razie, jak sugerujesz w swojej poprawce, myślę również, że lepiej jest odtworzyć obiekt. Może więc po prostu przechowywanie identyfikatora, a następnie na każde żądanie wyciągnięcie obiektu z bazy danych, jest lepsze / bezpieczniejsze.

Martyn
źródło