PHP: Memorizzazione di 'oggetti' all'interno di $ _SESSION


188

Ho appena capito che in realtà posso archiviare oggetti in $ _SESSION e lo trovo piuttosto interessante perché quando salto su un'altra pagina ho ancora il mio oggetto. Ora, prima di iniziare a utilizzare questo approccio, vorrei scoprire se è davvero una buona idea o se ci sono potenziali insidie .

So che se avessi un unico punto di entrata non avrei bisogno di farlo ma non ci sono ancora, quindi non ho un solo punto di entrata e vorrei davvero mantenere il mio oggetto perché non perdo il mio stato in quel modo. (Ora ho anche letto che dovrei programmare siti senza stato ma non capisco ancora quel concetto.)

Quindi in breve : va bene archiviare oggetti nella sessione, ci sono problemi con esso?


Modificare:

Riepilogo temporaneo : ormai capisco che probabilmente è meglio ricreare l'oggetto anche se comporta una nuova interrogazione del database.

Ulteriori risposte potrebbero forse approfondire un po 'di più questo aspetto !


13
Come ero 'stupido' nel 2008 :-)
markus

49
ma utile domanda a 'stupidi come noi nel 2014: D
Momin Al Aziz

3
Molto belle domande che hai fatto a markus .. :) L'ho letto oggi;)
gkd

1
Non eri stupido! Mi hai chiesto cosa stavo per chiedere e mi hai fatto un solido, 10 anni dopo!
toddmo

beh, immagino che mi hai appena salvato da una stupida domanda nel 2019
Maxwell,

Risposte:


133

So che questo argomento è vecchio, ma questo problema continua a presentarsi e non è stato affrontato con mia soddisfazione:

Sia che si salvino oggetti in $ _SESSION, sia che si ricostruisca l'intero tessuto in base ai dati nascosti nei campi modulo nascosti, o si eseguano nuovamente query dal DB ogni volta, si utilizza state. HTTP è apolide (più o meno; ma vedi GET vs. PUT) ma quasi tutto ciò che a qualcuno interessa fare con un'app Web richiede che lo stato sia mantenuto da qualche parte. Agire come se spingere lo stato in angoli e fessure equivale a una sorta di vittoria teorica è semplicemente sbagliato. Lo stato è stato. Se si utilizza lo stato, si perdono i vari vantaggi tecnici ottenuti dall'apolidia. Questo non è qualcosa per cui perdere il sonno se non sai in anticipo che dovresti perdere il sonno.

Sono particolarmente turbato dalla benedizione ricevuta dagli argomenti del "doppio scemo" proposti da Hank Gay. L'OP sta creando un sistema di e-commerce distribuito e bilanciato in base al carico? La mia ipotesi è no; e affermerò inoltre che la serializzazione della sua classe $ User, o qualsiasi altra cosa, non paralizzerà il suo server oltre la riparazione. Il mio consiglio: utilizzare tecniche sensibili alla propria applicazione. Gli oggetti in $ _SESSION vanno bene, soggetti a precauzioni di buon senso. Se la tua app si trasforma improvvisamente in qualcosa che rivaleggia con Amazon nel traffico servito, dovrai adattarti di nuovo. È la vita.


16
Bella risposta che incorpora molti dei miei pensieri mentre leggo questo. La moderna Internet ha bisogno di stato. Mentre alcune applicazioni non hanno bisogno di stato e hanno senso per rendere in modo apolide, la moderna Internet si affida a troppi sistemi basati sullo stato (AKA: Login!) Per rinunciarvi! I Grandi Dei di Internet hanno persino incorporato questo concetto di base per anni sotto forma di cookie e, a livello base, l'hanno aggiunto sotto forma di archiviazione locale in HTML. Potrebbe avere senso evitare un uso eccessivo dello stato in alcune applicazioni, ma alcune! = Tutto!
RonLugge,

Bene, quando ho posto quella domanda poco dopo che l'uomo ha inventato il fuoco, non sapevo molte cose che conosco oggi ... il che è altrettanto. Nel frattempo direi che potrebbero esserci alcuni buoni casi d'uso, ma generalmente cerco prima altre soluzioni. Contrassegnando ancora questa come la nuova risposta accettata perché l'altra risposta è categorica.
markus,

Pochissime risposte mi fanno ridere a crepapelle. Questo ha fatto. Bravo +1
toddmo

114

è OK fintanto che al momento della chiamata di session_start (), la dichiarazione / definizione di classe è già stata rilevata da PHP o può essere trovata da un caricatore automatico già installato. altrimenti non sarebbe in grado di deserializzare l'oggetto dall'archivio sessioni.


12
Grazie! Ciò ha risolto un bug per me: D
Matt Ellen,

Suppongo che questo problema potrebbe essere evitato se si dispone di una __autoload()funzione adeguata .
Langel,

Nell'annullare la serializzazione di un oggetto serializzato, dobbiamo aggiungere la definizione della classe ??? Al momento della serializzazione dell'oggetto è necessaria la definizione della classe, che sono d'accordo, ma devo aggiungere la definizione della classe anche nel file in cui devo serializzare l'oggetto serializzato ???
Rajesh Paul,

35

HTTP è un protocollo senza stato per un motivo. Stato della saldatura delle sessioni su HTTP. Come regola generale, evitare di utilizzare lo stato della sessione.

AGGIORNAMENTO: non esiste un concetto di sessione a livello HTTP; i server forniscono questo fornendo al client un ID univoco e dicendo al client di inviarlo nuovamente ad ogni richiesta. Quindi il server utilizza tale ID come chiave in una grande hashtable di oggetti Session. Ogni volta che il server riceve una richiesta, cerca le informazioni sulla sessione dalla sua hashtable di oggetti sessione in base all'ID che il client ha inviato con la richiesta. Tutto questo lavoro extra è un doppio senso della scalabilità (un grande motivo per cui HTTP è senza stato).

  • Whammy One: riduce il lavoro che un singolo server può fare.
  • Whammy Two: rende più difficile il ridimensionamento perché ora non puoi semplicemente indirizzare una richiesta a un vecchio server - non hanno tutti la stessa sessione. È possibile aggiungere tutte le richieste con un determinato ID sessione allo stesso server. Non è facile ed è un singolo punto di errore (non per il sistema nel suo complesso, ma per grossi blocchi di utenti). In alternativa, è possibile condividere l'archiviazione della sessione su tutti i server nel cluster, ma ora si ha una maggiore complessità: memoria collegata in rete, un server di sessione autonomo, ecc.

Ciò premesso, maggiore è il numero di informazioni inserite nella sessione, maggiore è l'impatto sulle prestazioni (come sottolineato da Vinko). Inoltre, come sottolinea Vinko, se il tuo oggetto non è serializzabile, la sessione si comporterà male. Quindi, come regola generale, evita di mettere più di quanto assolutamente necessario nella sessione.

@Vinko Di solito puoi aggirare lo stato dell'archivio server incorporando i dati che stai monitorando nella risposta che invii e facendo in modo che il client lo reinvii, ad esempio inviando i dati in un input nascosto. Se hai davvero bisogno del tracciamento dello stato sul lato server, probabilmente dovrebbe trovarsi nel tuo archivio dati di backup.

(Vinko aggiunge: PHP può utilizzare un database per archiviare le informazioni sulla sessione e avere il client che invia nuovamente i dati ogni volta potrebbe risolvere potenziali problemi di scalabilità, ma apre una grande lattina di problemi di sicurezza a cui devi prestare attenzione ora che il client ha il controllo di tutti il tuo stato)


1
Non esiste un concetto di sessione a livello HTTP; i server forniscono questo fornendo al client un ID univoco e dicendo al client di inviarlo nuovamente ad ogni richiesta. Quindi il server utilizza tale ID come chiave in una grande hashtable di oggetti Session. Continua ...
Hank Gay,

1
Ogni volta che il server riceve una richiesta, cerca le informazioni sulla sessione dalla sua hashtable di oggetti sessione in base all'ID che il client ha inviato con la richiesta. Tutto questo lavoro extra è un doppio scemo sulla scalabilità (un grande motivo per cui HTTP è senza stato). Continua ...
Hank Gay,

1
Mi chiedo come implementereste applicazioni complesse su HTTP senza stato di saldatura in qualche modo
Vinko Vrsalovic,

3
modifica la tua risposta per includere tutti questi commenti. è più facile da leggere e migliore per il wiki e comunque non posso scegliere la tua risposta come accettata, se tutto ciò che è importante nei commenti. Grazie!
markus,

6
"whammy one" Vorrei poter sottovalutare ulteriormente questo. Conosci i tuoi tempi. Un riferimento di memoria costa 100 nano secondi o 0,0001 ms. Quindi fare una ricerca su una tabella hash memorizzata nella memoria principale non costa letteralmente tempo. Ti O(1)dice qualcosa? @whammy two: semplicemente non indirizzare casualmente tutte le richieste verso server casuali? fare round robin e continuare a instradare allo stesso server dallo stesso utente. Questo è wow, super ovvio. Devi tornare sui tuoi libri, insieme a tutti i 30+ voti
Toskan

19
  • Gli oggetti che non possono essere serializzati (o che contengono membri non serializzabili) non usciranno da $ _SESSION come ci si aspetterebbe
  • Enormi sessioni mettono a dura prova il server (serializzare e deserializzare mega di stato ogni volta è costoso)

A parte questo, non ho visto problemi.


9

Nella mia esperienza, in genere non ne vale la pena per qualcosa di più complicato di una StdClass con alcune proprietà. Il costo della non serializzazione è sempre stato più che ricreare da un database dato un identificatore memorizzato nella sessione. Sembra interessante, ma (come sempre), la profilazione è la chiave.


Qualche commento sulle prestazioni tra l'interrogazione di una tabella di dati 5x2 ad ogni richiesta rispetto alla memorizzazione nella cache del risultato nella sessione e l'utilizzo di quello?
musicliftsme

6

Suggerirei di non usare lo stato se non ne hai assolutamente bisogno. Se riesci a ricostruire l'oggetto senza usare le sessioni, fallo. Avere stati nella tua applicazione web rende l'applicazione più complessa da costruire, per ogni richiesta devi vedere in che stato si trova l'utente. Ovviamente ci sono momenti in cui non puoi evitare di usare la sessione (esempio: l'utente deve mantenere l'accesso durante la sua sessione su l'applicazione web). Infine, suggerirei di mantenere l'oggetto sessione il più piccolo possibile in quanto influisce sulle prestazioni per serializzare e annullare la serializzazione di oggetti di grandi dimensioni.


Quindi, è meglio ricostruire l'oggetto includendo di nuovo tutte le query del database? Perché uno dei miei pensieri per fare questo è stato che non devo interrogare nuovamente il db per le stesse cose.
markus,

3
Se per te è importante che non esegua nuovamente la query nel database, utilizzare la memorizzazione nella cache anziché memorizzarla nella sessione. Ma per favore, prima di fare qualcosa come costruire la cache, controlla se è davvero un successo nelle prestazioni.
Johnny,

Grazie, penso proprio di no. Dovrei solo interrogare di nuovo.
markus,

4

Dovrai ricordare che i tipi di risorse (come connessioni db o puntatori di file) non persistono tra i caricamenti di pagina e dovrai ricrearli invisibilmente.

Considera anche la dimensione della sessione, a seconda di come è memorizzata, potresti avere restrizioni di dimensione o problemi di latenza.


0

Sollevo anche quando aggiorno le librerie del software - abbiamo aggiornato il nostro software e la vecchia versione aveva oggetti in sessione con i nomi di classe del software V1, il nuovo software si arrestava in modo anomalo quando tentava di costruire gli oggetti che erano nella sessione - come il V2 il software non usava più quelle stesse classi, non riusciva a trovarle. Abbiamo dovuto inserire un codice di correzione per rilevare gli oggetti sessione, eliminare la sessione se trovata, ricaricare la pagina. Il dolore più grande inizialmente mente che stavi ricreando questo bug quando è stato segnalato per la prima volta (fin troppo familiare, "beh, funziona per me" :) dato che riguardava solo le persone che erano dentro e fuori il vecchio e il nuovo sistema di recente - tuttavia, buono lavoro che abbiamo trovato prima del lancio in quanto tutti i nostri utenti avrebbero sicuramente avuto le vecchie variabili di sessione nelle loro sessioni e si sarebbero potenzialmente bloccati per tutti,

Comunque, come suggerisci nel tuo emendamento, penso anche che sia meglio ricreare l'oggetto. Quindi forse solo l'archiviazione dell'id e quindi su ogni richiesta che estrae l'oggetto dal database, è migliore / più sicura.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.