PHP: 在 $_ SESSION 中存储“对象”

我刚刚发现我可以实际上 在 $_ SESSION 中存储对象和我发现它相当酷,因为当我跳到另一个页面,我仍然有我的对象。现在,在我开始使用这种方法之前,我想知道它是否真的是一个好主意,或者是否涉及到 潜在的陷阱

我知道如果我有一个单一的进入点,我不需要这样做,但是我还没有到那里,所以我没有一个单一的进入点,我真的很想保留我的对象,因为我不会像那样失去我的状态。(现在我也读到我应该编写无状态站点程序,但是我还没有理解这个概念。)

那么 简而言之: 可以在会话中存储对象吗? 它有什么问题吗?


编辑:

临时摘要: 现在我明白了,它可能是 更适合重建的对象,即使它涉及到查询数据库了。

进一步的答案可能是 详细说明那方面的情况多一点!

99262 次浏览

只要在 session _ start ()调用之前,PHP 已经遇到了类声明/定义,或者已经安装的自动加载程序可以找到类声明/定义,那么就可以了。否则它将无法从会话存储区反序列化该对象。

HTTP 之所以是无状态协议是有原因的。HTTP 上的会话焊接状态。根据经验,避免使用会话状态。

< p > 更新: 在 HTTP 级别上没有会话的概念; 服务器通过给客户端一个惟一的 ID 并告诉客户端在每次请求时重新提交它来提供这个概念。然后服务器使用这个 ID 作为一个大的 Session 对象散列表的键。无论何时服务器收到请求,它都会根据客户机随请求一起提交的 ID 从会话对象的散列表中查找会话信息。所有这些额外的工作都是对可伸缩性的双重打击(HTTP 是无状态的一个重要原因)。译注:
  • 缺点一: 它减少了单个服务器可以做的工作。
  • 祸根二: 这使得扩展变得更加困难,因为现在你不能仅仅路由一个请求到任何一个旧的服务器——它们并不都有相同的会话。您可以将所有具有给定会话 ID 的请求固定到同一服务器。这并不容易,而且是单点故障(不是对整个系统而言,而是对大部分用户而言)。或者,您可以跨集群中的所有服务器共享会话存储,但是现在您有了更多的复杂性: 网络附加内存、独立会话服务器等等。

考虑到所有这些,你在会话中放入的信息越多,对性能的影响就越大(正如 Vinko 指出的那样)。另外,正如 Vinko 指出的,如果您的对象不可序列化,那么会话将会出现错误。因此,根据经验法则,避免在会话中放置超过绝对必要的内容。

@ Vinko 通常情况下,你可以把跟踪的数据嵌入到发送回来的响应中,然后让客户端重新提交,比如把数据发送到一个隐藏的输入端,这样就可以解决服务器存储状态的问题。如果您的 真的需要在服务器端跟踪状态,那么它应该在您的后台数据存储中。

(Vinko 补充道: PHP 可以使用一个数据库来存储会话信息,让客户机每次重新提交数据可能会解决潜在的可伸缩性问题,但是这会带来一大堆安全问题,现在客户机已经控制了你的所有状态,你必须注意这些问题)

  • 不能序列化的对象(或包含不可序列化成员的对象)不会像您期望的那样从 $_ SESSION 中出来
  • 巨大的会话给服务器带来了负担(每次序列化和反序列化兆状态的开销都很大)

除此之外,我没看到任何问题。

您必须记住,资源类型(如数据库连接或文件指针)不会在页面加载之间持久存在,并且需要在不可见的情况下重新创建这些资源类型。

还要考虑会话的大小,这取决于它的存储方式,您可能有大小限制或延迟问题。

我建议不要使用 state,除非你绝对需要它。如果可以不使用会话重新生成对象,则执行此操作。 在 Web 应用程序中设置状态会使应用程序的构建更加复杂,对于每个请求,您都必须查看用户的状态。当然,有些时候你不能避免使用 session (例如: 用户必须在 Web 应用程序的 session 中保持登录)。 最后,我建议尽可能保持会话对象小,因为序列化和取消序列化大型对象会影响性能。译注:

根据我的经验,对于任何比具有某些属性的 StdClass 更复杂的东西,通常都不值得这样做。取消序列化的成本总是比从给定会话存储标识符的数据库中重新创建的成本更高。这看起来很酷,但是(像往常一样) ,侧写是关键。

我知道这个话题很老了,但是这个问题一直在提,而且没有得到令我满意的解决:

无论您是将对象保存在 $_ SESSION 中,还是根据隐藏在表单字段中的数据重新构建它们,或者每次从 DB 中重新查询它们,您都在使用状态。HTTP 是无状态的(或多或少; 但是参见 GET 与 PUT) ,但是几乎所有人关心的 Web 应用都需要在某个地方维护状态。好像把政府推到角落和缝隙就等于某种理论上的胜利,这种做法是错误的。国家就是国家。如果使用 state,则会失去通过无状态获得的各种技术优势。除非你事先知道你应该为此而失眠,否则这不是什么值得失眠的事情。

我对汉克 · 盖伊提出的“双重打击”论点所得到的祝福感到特别困惑。OP 是否构建了一个分布式的、负载均衡的电子商务系统?我的猜测是否定的; 并且我将进一步假定序列化他的 $User 类或其他类不会使他的服务器瘫痪到无法修复的地步。我的建议是: 使用对应用程序合理的技术。$_ SESSION 中的对象没有问题,需要遵守常识性的预防措施。如果你的应用程序突然变得可以在流量上与亚马逊匹敌,你需要重新适应。这就是生活。

我也会在升级软件库的时候提到这个问题——我们升级了我们的软件,旧版本的会话中有 V1软件的类名,新版本的软件在构建会话中的对象时崩溃了——因为 V2软件不再使用那些相同的类,它找不到它们了。我们必须放入一些修复代码来检测会话对象,如果找到会话就删除它,重新加载页面。当这个 bug 第一次被报道的时候,你最初想到的最大的痛苦就是重新创建这个 bug (太熟悉了,“嗯,它对我很有用”:) ,因为它只会影响最近进出新旧系统的人们——然而,我们在发布之前发现了它,因为我们所有的用户肯定会在他们的会话中有旧的会话变量,并且可能会全部崩溃,这将是一个糟糕的发布:)

无论如何,正如你在修正案中所建议的,我也认为最好重新创建这个物体。因此,也许只存储 id,然后在每个请求中从数据库中提取对象,是更好/更安全的做法。