PHP: Almacenar 'objetos' dentro de $ _SESSION

188

Acabo de darme cuenta de que en realidad puedo almacenar objetos en $ _SESSION y me parece bastante genial porque cuando salto a otra página todavía tengo mi objeto. Ahora, antes de comenzar a usar este enfoque, me gustaría saber si realmente es una buena idea o si existen posibles dificultades .

Sé que si tuviera un único punto de entrada, no necesitaría hacerlo, pero todavía no estoy allí, así que no tengo un solo punto de entrada y realmente me gustaría mantener mi objeto porque no No pierdo mi estado así. (Ahora también he leído que debo programar sitios sin estado pero todavía no entiendo ese concepto).

En resumen : ¿está bien almacenar objetos en la sesión? ¿Hay algún problema con eso?


Editar:

Resumen temporal : por ahora entiendo que probablemente sea mejor recrear el objeto incluso si implica consultar nuevamente la base de datos.

¡Más respuestas tal vez podrían dar más detalles sobre ese aspecto !

Markus
fuente
13
Qué 'estúpido' fui en 2008 :-)
markus
49
pero una pregunta útil para 'estúpidos como nosotros en 2014: D
Momin Al Aziz
3
Muy buenas preguntas que le has hecho a Markus .. :) Lo leí hoy;)
gkd
1
No eras estúpido! ¡Me preguntaste lo que estaba a punto de preguntar y me hiciste un sólido 10 años después!
toddmo
Bueno, supongo que me salvaste de hacer una pregunta estúpida en 2019
Maxwell

Respuestas:

133

Sé que este tema es antiguo, pero este problema sigue apareciendo y no se ha abordado a mi entera satisfacción:

Ya sea que guarde objetos en $ _SESSION, o los reconstruya con un paño completo basado en datos escondidos en campos de formulario ocultos, o vuelva a consultarlos desde la base de datos cada vez, está utilizando el estado. HTTP no tiene estado (más o menos; pero vea GET vs.PUT), pero casi todo lo que a alguien le importa hacer con una aplicación web requiere que el estado se mantenga en algún lugar. Actuar como si empujar al estado a los rincones y grietas equivale a algún tipo de victoria teórica es simplemente incorrecto. Estado es estado. Si usa el estado, pierde las diversas ventajas técnicas obtenidas al no tener estado. Esto no es algo para perder el sueño a menos que sepa de antemano que debería perder el sueño por eso.

Estoy especialmente desconcertado por la bendición recibida por los argumentos de "doble golpe" presentados por Hank Gay. ¿El OP está construyendo un sistema de comercio electrónico distribuido y con equilibrio de carga? Mi conjetura es no; y postularé que serializar su clase $ User, o lo que sea, no paralizará su servidor sin posibilidad de reparación. Mi consejo: utilice técnicas que sean sensibles a su aplicación. Los objetos en $ _SESSION están bien, sujetos a precauciones de sentido común. Si su aplicación de repente se convierte en algo que rivaliza con Amazon en el tráfico servido, deberá volver a adaptarse. Así es la vida.

shanusmagnus
fuente
16
Buena respuesta incorporando muchos de mis propios pensamientos mientras leía esto. El internet moderno necesita estado. Si bien algunas aplicaciones no necesitan estado y tienen sentido para tener una forma apátrida, Internet moderno se basa en demasiados sistemas basados ​​en estado (AKA: ¡Inicios de sesión!) Para simplemente abandonarlos. Los Grandes Dioses de Internet incluso han incorporado ese concepto básico durante años en forma de cookies, y en un nivel básico lo han agregado en forma de almacenamiento local en HTML. Puede tener sentido evitar el uso excesivo del estado en algunas aplicaciones, pero some! = All!
RonLugge
Bueno, cuando hice esa pregunta poco después de que el hombre inventó el fuego, no sabía muchas cosas que sé hoy ... lo cual es igual de bueno. Mientras tanto, diría que puede haber algunos buenos casos de uso, pero generalmente buscaría otras soluciones primero. Todavía marca esto como la nueva respuesta aceptada porque la otra respuesta es categórica.
markus
Muy pocas respuestas me hacen reír a carcajadas. Este lo hizo. Bravo +1
toddmo
114

está bien siempre y cuando se realice la llamada session_start (), la declaración / definición de clase ya ha sido encontrada por PHP o puede ser encontrada por un cargador automático ya instalado. de lo contrario no podría deserializar el objeto del almacén de sesiones.

crucero
fuente
12
¡Gracias! Eso solucionó un error para mí: D
Matt Ellen
Supongo que este problema podría evitarse si tiene una __autoload()función adecuada .
Langel
Al deserializar un objeto serializado, ¿tenemos que agregar la definición de clase? Al momento de serializar el objeto, necesita la definición de clase, eso estoy de acuerdo, pero ¿tengo que agregar la definición de clase también en el archivo donde tengo que deserializar el objeto serializado?
Rajesh Paul
35

HTTP es un protocolo sin estado por una razón. Las sesiones sueldan el estado en HTTP. Como regla general, evite usar el estado de sesión.

ACTUALIZACIÓN: No existe el concepto de una sesión en el nivel HTTP; los servidores proporcionan esto al darle al cliente un ID único y decirle al cliente que lo vuelva a enviar en cada solicitud. Luego, el servidor usa esa ID como clave en una gran tabla hash de objetos de sesión. Cada vez que el servidor recibe una solicitud, busca la información de la sesión fuera de su tabla hash de objetos de sesión en función de la ID que el cliente envió con la solicitud. Todo este trabajo adicional es un doble golpe para la escalabilidad (una gran razón por la cual HTTP no tiene estado).

  • Whammy One: Reduce el trabajo que puede hacer un solo servidor.
  • Whammy Two: hace que sea más difícil de escalar porque ahora no puede enrutar una solicitud a cualquier servidor antiguo, no todos tienen la misma sesión. Puede anclar todas las solicitudes con una ID de sesión determinada al mismo servidor. Eso no es fácil, y es un punto único de falla (no para el sistema en su conjunto, sino para grandes partes de sus usuarios). O bien, podría compartir el almacenamiento de la sesión en todos los servidores del clúster, pero ahora tiene más complejidad: memoria conectada a la red, un servidor de sesión independiente, etc.

Dado todo eso, cuanta más información pongas en la sesión, mayor será el impacto en el rendimiento (como señala Vinko). Además, como señala Vinko, si su objeto no es serializable, la sesión se comportará mal. Por lo tanto, como regla general, evite poner más de lo absolutamente necesario en la sesión.

@Vinko Por lo general, puede evitar que el servidor almacene el estado incorporando los datos que está rastreando en la respuesta que envía y haciendo que el cliente vuelva a enviarlos, por ejemplo, enviando los datos en una entrada oculta. Si realmente necesita un seguimiento del estado del lado del servidor, probablemente debería estar en su almacén de datos de respaldo.

(Vinko agrega: PHP puede usar una base de datos para almacenar información de sesión, y hacer que el cliente vuelva a enviar los datos cada vez puede resolver posibles problemas de escalabilidad, pero abre una gran lata de problemas de seguridad a los que debe prestar atención ahora que el cliente tiene el control de todo tu estado)

Hank Gay
fuente
1
No existe el concepto de una sesión en el nivel HTTP; los servidores proporcionan esto al darle al cliente una identificación única y decirle al cliente que vuelva a enviarlo en cada solicitud. Luego, el servidor usa esa ID como clave en una gran tabla hash de objetos de sesión. Continuará ...
Hank Gay
1
Cada vez que el servidor recibe una solicitud, busca la información de la sesión fuera de su tabla hash de objetos de sesión en función de la ID que el cliente envió con la solicitud. Todo este trabajo adicional es un doble golpe para la escalabilidad (una gran razón por la cual HTTP no tiene estado). Continuará ...
Hank Gay
1
Me pregunto cómo implementar aplicaciones complejas sobre HTTP sin estado de soldadura de alguna manera
Vinko Vrsalovic
3
edite su respuesta para incluir todos estos comentarios. es más fácil de leer y mejor para la wiki y de todos modos no puedo elegir tu respuesta como la aceptada, si todo lo importante está en los comentarios. ¡Gracias!
markus
66
"Whammy one" Ojalá pudiera menospreciar esto más. Conoce tu momento. Una referencia de memoria cuesta 100 nano segundos, o 0.0001 ms. Por lo tanto, hacer una búsqueda en una tabla hash que se almacena en la memoria principal literalmente no cuesta tiempo. ¿ O(1)Te dice algo? @whammy two: ¿simplemente no enruta al azar todas las solicitudes a servidores aleatorios? hacer round robin y seguir enrutando al mismo servidor desde el mismo usuario. Esto es wow, super obvio. Tienes que revisar tus libros, junto con los más de 30 votos a favor
Toskan
19
  • Los objetos que no se pueden serializar (o que contienen miembros no serializables) no saldrán de $ _SESSION como cabría esperar
  • Las sesiones enormes suponen una carga para el servidor (serializar y deserializar megas de estado cada vez es costoso)

Aparte de eso, no he visto ningún problema.

Vinko Vrsalovic
fuente
9

En mi experiencia, generalmente no vale la pena por algo más complicado que un StdClass con algunas propiedades. El costo de la deserialización siempre ha sido más que recrear desde una base de datos con un identificador almacenado en la sesión. Parece genial, pero (como siempre), el perfil es la clave.

Greg
fuente
¿Algún comentario sobre el rendimiento entre consultar una tabla de datos de 5x2 en cada solicitud frente al almacenamiento en caché del resultado en la sesión y usar eso?
musicliftsme
6

Sugeriría no usar el estado a menos que lo necesite absolutamente. Si puede reconstruir el objeto sin usar sesiones, hágalo. Tener estados en su aplicación web hace que la aplicación sea más compleja de construir, para cada solicitud tiene que ver en qué estado se encuentra el usuario. Por supuesto, hay momentos en los que no puede evitar usar la sesión (ejemplo: el usuario debe mantener el inicio de sesión durante su sesión en la aplicación web). Por último, sugeriría mantener su objeto de sesión lo más pequeño posible, ya que afecta el rendimiento para serializar y deserializar objetos grandes.

Johnny
fuente
Entonces, ¿es mejor reconstruir el objeto incluyendo hacer todas las consultas de la base de datos nuevamente? Debido a que uno de mis pensamientos para hacer esto fue que no tengo que consultar al db por las mismas cosas nuevamente.
markus
3
Si es importante para usted que no vuelva a consultar la base de datos, use el almacenamiento en caché en lugar de almacenarlo en la sesión. Pero, por favor, antes de hacer algo como construir caché, verifique si realmente es un éxito en el rendimiento.
Johnny
Gracias, en realidad creo que no lo es. Debería consultar nuevamente.
markus
4

Deberá recordar que los tipos de recursos (como las conexiones db o los punteros de archivo) no persistirán entre las cargas de la página, y deberá volver a crearlos de forma invisible.

Considere también el tamaño de la sesión, dependiendo de cómo se almacene, puede tener restricciones de tamaño o problemas de latencia.

Marc Gear
fuente
0

También aparecería al actualizar las bibliotecas de software: actualizamos nuestro software y la versión anterior tenía objetos en sesión con los nombres de clase del software V1, el nuevo software se bloqueaba cuando intentaba construir los objetos que estaban en la sesión, como el V2 el software ya no usaba esas mismas clases, no podía encontrarlas. Tuvimos que poner un código de corrección para detectar objetos de sesión, eliminar la sesión si se encontraba, volver a cargar la página. Al principio, el mayor dolor era que estaba recreando este error cuando se informó por primera vez (muy familiar, "bueno, funciona para mí" :) ya que solo afectó a las personas que ingresaron y salieron de los sistemas antiguos y nuevos recientemente, sin embargo, bueno trabajo lo encontramos antes del lanzamiento ya que todos nuestros usuarios seguramente habrían tenido las antiguas variables de sesión en sus sesiones y potencialmente se habrían bloqueado para todos,

De todos modos, como sugiere en su enmienda, también creo que es mejor volver a crear el objeto. Entonces, tal vez solo almacenar la identificación y luego, en cada solicitud, extraer el objeto de la base de datos, sea mejor / más seguro.

Martyn
fuente