193

I just figured out that I can actually store objects in the $_SESSION and I find it quite cool because when I jump to another page I still have my object. Now before I start using this approach I would like to find out if it is really such a good idea or if there are potential pitfalls involved.

I know that if I had a single point of entry I wouldn't need to do that but I'm not there yet so I don't have a single point of entry and I would really like to keep my object because I don't lose my state like that. (Now I've also read that I should program stateless sites but I don't understand that concept yet.)

So in short: Is it ok to store objects in the session, are there any problems with it?


Edit:

Temporary summary: By now I understand that it is probably better to recreate the object even if it involves querying the database again.

Further answers could maybe elaborate on that aspect a bit more!

markus
  • 40,136
  • 23
  • 97
  • 142
  • 14
    How 'stupid' I was in 2008 :-) – markus Dec 08 '13 at 14:59
  • 51
    but useful question to 'stupid's like us in 2014 :D – Gun2sh Jan 02 '14 at 21:32
  • 3
    Very nice questions you have asked markus.. :) I read it today ;) – gkd Jun 27 '14 at 07:29
  • 2
    You weren't stupid! You asked what I was about to ask and did me a solid, 10 years later! – toddmo Mar 27 '18 at 18:21
  • 2
    well, i guessed you just saved me from asking a stupid question in 2019 – Maxwell Mar 27 '19 at 11:54
  • Just to add to this - I ran into ALL KINDS of weird issues with PHP 7.1 storing my full $user object in the session... in the end it was easy to just keep track of the userID and recreate the object on page load... and boom all my bugs disappeared. – Eric Jul 13 '19 at 16:01

8 Answers8

139

I know this topic is old, but this issue keeps coming up and has not been addressed to my satisfaction:

Whether you save objects in $_SESSION, or reconstruct them whole cloth based on data stashed in hidden form fields, or re-query them from the DB each time, you are using state. HTTP is stateless (more or less; but see GET vs. PUT) but almost everything anybody cares to do with a web app requires state to be maintained somewhere. Acting as if pushing the state into nooks and crannies amounts to some kind of theoretical win is just wrong. State is state. If you use state, you lose the various technical advantages gained by being stateless. This is not something to lose sleep over unless you know in advance that you ought to be losing sleep over it.

I am especially flummoxed by the blessing received by the "double whammy" arguments put forth by Hank Gay. Is the OP building a distributed and load-balanced e-commerce system? My guess is no; and I will further posit that serializing his $User class, or whatever, will not cripple his server beyond repair. My advice: use techniques that are sensible to your application. Objects in $_SESSION are fine, subject to common sense precautions. If your app suddenly turns into something rivaling Amazon in traffic served, you will need to re-adapt. That's life.

shanusmagnus
  • 2,340
  • 2
  • 20
  • 19
  • 18
    Nice answer incorporating a lot of my own thoughts as I've been reading through this. The modern internet _needs_ state. While some applications don't need state and make sense to make in a stateless manner, the modern internet relies on too many systems that are based on state (AKA: Logins!) to just give them up! The Great Gods of the internet have even incorporated that basic concept in for years in the form of cookies, and at a basic level they've added it in the form of local storage in HTML. It might make sense to avoid excessive use of state in _some_ applications, but some != all! – RonLugge Mar 29 '12 at 06:28
  • Well, when I asked that question shortly after man invented fire, I didn't know a lot of things I know today... which is just as well. In the meantime I'd say there may be a few good use cases but generally I'd look for other solutions first. Still marking this as the new accepted answer because the other answer is to categorical. – markus Feb 17 '13 at 21:58
  • Very few answers make me laugh out loud. This one did. Bravo +1 – toddmo Mar 27 '18 at 18:21
114

it's OK as long as by the time the session_start() call is made, the class declaration/definition has already been encountered by PHP or can be found by an already-installed autoloader. otherwise it would not be able to deserialize the object from the session store.

mindplay.dk
  • 7,085
  • 3
  • 44
  • 54
cruizer
  • 6,103
  • 2
  • 27
  • 34
  • I am assuming that this problem could be avoided if you have a proper `__autoload()` function. – Langel Jun 18 '13 at 20:02
  • In unserializing a serialized object do we have to add the class definition??? At the time of serializing the object it needs the class definition, that I agree, But do I have to add the class definition also in the file where I have to unserialize the serialized object??? – Rajesh Paul Sep 20 '13 at 19:08
35

HTTP is a stateless protocol for a reason. Sessions weld state onto HTTP. As a rule of thumb, avoid using session state.

UPDATE: There is no concept of a session at the HTTP level; servers provide this by giving the client a unique ID and telling the client to resubmit it on every request. Then the server uses that ID as a key into a big hashtable of Session objects. Whenever the server gets a request, it looks up the Session info out of its hashtable of session objects based on the ID the client submitted with the request. All this extra work is a double whammy on scalability (a big reason HTTP is stateless).

  • Whammy One: It reduces the work a single server can do.
  • Whammy Two: It makes it harder to scale out because now you can't just route a request to any old server - they don't all have the same session. You can pin all the requests with a given session ID to the same server. That's not easy, and it's a single point of failure (not for the system as a whole, but for big chunks of your users). Or, you could share the session storage across all servers in the cluster, but now you have more complexity: network-attached memory, a stand-alone session server, etc.

Given all that, the more info you put in the session, the bigger the impact on performance (as Vinko points out). Also as Vinko points out, if your object isn't serializable, the session will misbehave. So, as a rule of thumb, avoid putting more than absolutely necessary in the session.

@Vinko You can usually work around having the server store state by embedding the data you're tracking in the response you send back and having the client resubmit it, e.g., sending the data down in a hidden input. If you really need server-side tracking of state, it should probably be in your backing datastore.

(Vinko adds: PHP can use a database for storing session information, and having the client resubmit the data each time might solve potential scalability issues, but opens a big can of security issues you must pay attention to now that the client's in control of all your state)

Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
Hank Gay
  • 70,339
  • 36
  • 160
  • 222
  • weld? what do you mean? can you explain your point in more details and why is it a rule of thumb? – markus Sep 25 '08 at 08:56
  • 1
    There is no concept of a session at the HTTP level; servers provide this by giving the client a unique ID and telling the client to resubmit it on every request. Then the server uses that ID as a key into a big hashtable of Session objects. To be continued… – Hank Gay Sep 25 '08 at 09:00
  • 1
    Whenever the server gets a request, it looks up the Session info out of its hashtable of session objects based on the ID the client submitted with the request. All this extra work is a double whammy on scalability (a big reason HTTP is stateless). To be continued… – Hank Gay Sep 25 '08 at 09:03
  • 1
    I wonder how would you implement complex applications over HTTP without welding state somehow – Vinko Vrsalovic Sep 25 '08 at 09:04
  • Whammy One: It reduces the work a single server can do. Whammy Two: It makes it harder to scale out because now you can't just route a request to any old server - they don't all have the same session. To be continued… – Hank Gay Sep 25 '08 at 09:05
  • You can pin all the requests with a given session ID to the same server. That's not easy, and it's a single point of failure. Or, you could share the session storage across all servers in the cluster, but now you have more complexity: network-attached memory, a stand-alone session server, etc. TBC… – Hank Gay Sep 25 '08 at 09:06
  • Given all that, the more info you put in the session, the bigger the impact on performance (as Vinko points out). Also as Vinko points out, if your object isn't serializable, the session will misbehave. So, as a rule of thumb, avoid putting more than absolutely necessary in the session. TBC… – Hank Gay Sep 25 '08 at 09:09
  • @Vinko You can usually work around having the server store state by embedding the data you're tracking in the response you send back and having the client resubmit, e.g., a hidden input. If you *really* need server-side tracking of state, it should probably be in your backing datastore. – Hank Gay Sep 25 '08 at 09:11
  • 3
    please edit your answer to include all these comments. it's easier to read and better for the wiki and anyways I can't chose your answer as the accepted one, if everything important is in the comments. thanks! – markus Sep 25 '08 at 09:13
  • You make it sound like sessions is the root of all evil code, its not. On larger dynamic sites its hard not to use sessions. Not so sure its a good thing to use it for objects though – John Jun 28 '10 at 03:11
  • Your "backing datastore" (if you're not using sessions) and the "network-attached memory" (for storing sessions) can easily be the same service, e.g. by using MySQL as your session store. In that case, there's no inherent disadvantage for using sessions. – thenickdude Jan 13 '12 at 08:15
  • 6
    "whammy one" I wish I could downvote this more. Know your timing. A memory reference costs 100 nano seconds, or 0.0001 ms. So doing a lookup on a hashtable that is stored in main memory literally costs no time. Does `O(1)` tell you something? @whammy two: just don't randomly route all requests to random servers? do round robin, and keep routing to the same server from same user. This is wow, super obvious. You have to go back over your books, along with all 30+ upvotes – Toskan Jun 14 '14 at 00:53
  • "Whammy Two" is negated if you are storing sessions in a database. PHP has a method that makes doing this extremely simple (session_set_save_handler()). – Jabari Feb 09 '15 at 22:58
  • @Toskan "whammy one" isn't about CPU, it's about memory. People inevitably wind up with **much** more stuff in the session than they realize; it's just so easy. From a CPU/time perspective, the only "slow" thing about the hashtable-based version of a session would be whenever it has to grow: once it's big enough, it can be a challenge to suddenly allocate such a gigantic chunk of contiguous memory (because you might not have that much, and suddenly the GC/runtime has to rearrange "free" pages, compact trash, etc.). – Hank Gay Feb 10 '15 at 14:28
  • @HankGay where did I say it is about CPU? Something that does not belong to the session, does not belong there, yeah. – Toskan Feb 12 '15 at 03:43
  • 1
    @Toskan In my experience, the only way to keep out "something that does not belong to the session" is to assume that nothing belongs in the session until you convince the rest of the team it does. Even then, it's a good idea to go back and review, because it's easy for somebody to accidentally add a (potentially memory-intensive) property to some object that is being serialized into the session by some other chunk of code, and suddenly you're having to spin up more servers because of some mysterious "memory leak". I don't disagree that the session has its uses; I just believe it is overused. – Hank Gay Feb 12 '15 at 19:20
  • A caution for anyone considering this advice, yes it's easy to keep session data in the database using PHP but beware of performance for busy servers. If you're doing more than a couple of dozen requests per second you will see a significant performance hit. The default file based session system is much faster than the database. If you have to scale over multiple servers you can always shard the data and keep each user assigned to a specific server so they will never lose session. – Vincent Jul 08 '19 at 23:20
20
  • Objects which cannot be serialized (or which contain unserializable members) will not come out of the $_SESSION as you would expect
  • Huge sessions put a burden on the server (serializing and deserializing megs of state each time is expensive)

Other than that I've seen no problems.

Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
11

In my experience, it's generally not worth it for anything more complicated than an StdClass with some properties. The cost of unserializing has always been more than recreating from a database given a session-stored Identifier. It seems cool, but (as always), profiling is the key.

Greg
  • 10,350
  • 1
  • 26
  • 35
  • Any comment on performances between querying a 5x2 table of data at every request vs. caching the result in session and using that? – laketuna Dec 08 '15 at 20:32
8

I would suggest don't use state unless you absolutely need it. If you can rebuild the object without using sessions do it. Having states in your webapplication makes the application more complex to build, for every request you have to see what state the user is in. Ofcourse there are times where you cannot avoid using session (example: user have to be kept login during his session on the webapplication). Last I would suggest keeping your session object as small as possible as it impacts performance to serialize and unserialize large objects.

Johnny
  • 437
  • 4
  • 8
  • So, is it better to rebuild the object including doing all the database queries again? Because one of my thoughts for doing this was that I don't have to query the db for the same stuff again. – markus Sep 25 '08 at 09:05
  • 3
    If it's important to you that it won't query the database again use caching instead of storing it in the session. But please before doing anything like building caching check whether it is really a performance hit. – Johnny Sep 25 '08 at 09:46
  • Thanks, I actually think it's not. I should just query again. – markus Sep 25 '08 at 10:00
4

You'll have to remember that resource types (such as db connections or file pointers) wont persist between page loads, and you'll need to invisibly re-create these.

Also consider the size of the session, depending how it is stored, you may have size restrictions, or latency issues.

Marc Gear
  • 2,757
  • 1
  • 20
  • 19
1

I would also bring up when upgrading software libraries - we upgraded our software and the old version had objects in session with the V1 software's class names, the new software was crashing when it tried to build the objects that were in the session - as the V2 software didn't use those same classes anymore, it couldn't find them. We had to put in some fix code to detect session objects, delete the session if found, reload the page. The biggest pain initially mind you was recreating this bug when it was first reported (all too familiar, "well, it works for me" :) as it only affected people who where in and out the old and new systems recently - however, good job we did find it before launch as all of our users would surely have had the old session variables in their sessions and would have potentially crashed for all, would have been a terrible launch :)

Anyway, as you suggest in your amendment, I also think it's better to re-create the object. So maybe just storing id and then on each request pulling the object from the database, is better/safer.

Martyn
  • 6,031
  • 12
  • 55
  • 121