PHP:在 $_SESSION 中存储“对象”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/132194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP: Storing 'objects' inside the $_SESSION
提问by markus
I just figured out that I can actually store objects in the $_SESSIONand 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 pitfallsinvolved.
我刚刚发现我实际上可以在 $_SESSION 中存储对象,我觉得它很酷,因为当我跳转到另一个页面时,我仍然拥有我的对象。现在,在我开始使用这种方法之前,我想知道这是否真的是一个好主意,或者是否存在潜在的陷阱。
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 recreatethe object even if it involves querying the database again.
临时摘要:现在我明白重新创建对象可能更好,即使它涉及再次查询数据库。
Further answers could maybe elaborate on that aspecta bit more!
进一步的答案可能会详细说明这一方面!
采纳答案by shanusmagnus
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.
无论是将对象保存在 $_SESSION 中,还是根据隐藏在表单字段中的数据重建它们,或者每次都从数据库中重新查询它们,您都在使用状态。HTTP 是无状态的(或多或少;但请参阅 GET 与 PUT),但几乎任何人关心的 Web 应用程序都需要在某处维护状态。好像把国家推向角落和缝隙就等于某种理论上的胜利是错误的。状态就是状态。如果您使用状态,您将失去通过无状态获得的各种技术优势。除非您事先知道您应该为此失眠,否则这不是值得失眠的事情。
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.
汉克·盖伊 (Hank Gay) 提出的“双重打击”论点所带来的祝福让我特别困惑。OP 是否正在构建分布式和负载均衡的电子商务系统?我的猜测是否定的;并且我将进一步假定序列化他的 $User 类或其他类不会使他的服务器无法修复。我的建议是:使用适合您的应用程序的技术。$_SESSION 中的对象没有问题,但要遵守常识预防措施。如果您的应用突然变成在服务流量方面与亚马逊相媲美的东西,您将需要重新适应。这就是生活。
回答by cruizer
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.
只要在 session_start() 调用时,类声明/定义已经被 PHP 遇到或者可以被已经安装的自动加载器找到,就可以了。否则它将无法从会话存储中反序列化对象。
回答by Hank Gay
HTTP is a stateless protocol for a reason. Sessions weld state onto HTTP. As a rule of thumb, avoid using session state.
HTTP 是无状态协议是有原因的。会话将状态焊接到 HTTP 上。根据经验,避免使用会话状态。
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).
更新:在 HTTP 级别没有会话的概念;服务器通过为客户端提供唯一 ID 并告诉客户端在每次请求时重新提交它来提供此功能。然后服务器使用该 ID 作为 Session 对象的大哈希表的键。每当服务器收到请求时,它都会根据客户端随请求提交的 ID 从其会话对象的哈希表中查找会话信息。所有这些额外的工作都是对可扩展性的双重打击(HTTP 是无状态的一个重要原因)。
- 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.
- Whammy One:它减少了单个服务器可以完成的工作。
- 缺点二:这使得横向扩展变得更加困难,因为现在您不能仅仅将请求路由到任何旧服务器——它们并不都具有相同的会话。您可以将具有给定会话 ID 的所有请求固定到同一服务器。这并不容易,而且是单点故障(不是针对整个系统,而是针对大量用户)。或者,您可以在集群中的所有服务器之间共享会话存储,但现在您有更多的复杂性:网络附加内存、独立会话服务器等。
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 指出的那样)。同样正如 Vinko 指出的那样,如果您的对象不可序列化,则会话将行为不端。因此,根据经验,避免在会话中放置超过绝对必要的内容。
@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 reallyneed server-side tracking of state, it should probably be in your backing datastore.
@Vinko您通常可以通过将您正在跟踪的数据嵌入您发回的响应中并让客户端重新提交它来解决服务器存储状态,例如,将数据发送到隐藏的输入中。如果您确实需要服务器端状态跟踪,它可能应该在您的后备数据存储中。
(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 补充道:PHP 可以使用数据库来存储会话信息,并且每次让客户端重新提交数据可能会解决潜在的可扩展性问题,但是打开了一大堆安全问题,您现在必须注意客户端控制所有您的国家)
回答by Vinko Vrsalovic
- 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)
- 无法序列化的对象(或包含不可序列化的成员)不会像您期望的那样从 $_SESSION 中出来
- 巨大的会话给服务器带来了负担(每次对状态进行序列化和反序列化都很昂贵)
Other than that I've seen no problems.
除此之外,我没有看到任何问题。
回答by Greg
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.
根据我的经验,对于比具有某些属性的 StdClass 更复杂的东西,通常不值得。反序列化的成本始终高于从给定会话存储标识符的数据库中重新创建。看起来很酷,但是(一如既往),分析是关键。
回答by Johnny
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.
我建议不要使用 state 除非你绝对需要它。如果您可以在不使用会话的情况下重建对象,请执行此操作。在 Web 应用程序中拥有状态会使应用程序构建起来更加复杂,对于每个请求,您都必须查看用户所处的状态。当然,有时您无法避免使用会话(例如:用户必须在会话期间保持登录状态)网络应用程序)。最后,我建议让您的会话对象尽可能小,因为它会影响序列化和反序列化大对象的性能。
回答by Marc Gear
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.
还要考虑会话的大小,取决于它的存储方式,您可能有大小限制或延迟问题。
回答by Martyn
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 :)
在升级软件库时我也会提到 - 我们升级了我们的软件,旧版本的对象与 V1 软件的类名会话,新软件在尝试构建会话中的对象时崩溃 - 作为 V2软件不再使用那些相同的类,它找不到它们。我们不得不放入一些修复代码来检测会话对象,如果找到就删除会话,重新加载页面。最初最大的痛苦是你在第一次报告时重新创建了这个错误(太熟悉了,“好吧,它对我有用”:)因为它只影响最近进出新旧系统的人 - 但是,很好我们确实在发布之前找到了它,因为我们所有的用户肯定会在他们的会话中拥有旧的会话变量,并且可能会崩溃,
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.
无论如何,正如您在修正案中所建议的那样,我也认为最好重新创建该对象。所以也许只是存储 id 然后在每个请求上从数据库中提取对象,更好/更安全。

