192

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

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

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


编辑:

临时总结:到目前为止,我知道重新创建对象可能会更好,即使它涉及再次查询数据库。

进一步的答案可能会更详细地说明这方面

4

8 回答 8

138

我知道这个话题已经过时了,但是这个问题不断出现,并且没有让我满意:

无论您将对象保存在 $_SESSION 中,还是根据隐藏在表单字段中的数据重建它们,或者每次从数据库中重新查询它们,您都在使用状态。HTTP 是无状态的(或多或少;但请参阅 GET 与 PUT),但几乎任何人关心的 Web 应用程序都需要在某处维护状态。表现得好像将国家推入角落和缝隙相当于某种理论上的胜利是错误的。国家就是国家。如果您使用状态,您将失去无状态所获得的各种技术优势。除非你事先知道你应该为此失眠,否则这不是失眠的事情。

我对汉克·盖伊提出的“双重打击”论点所获得的祝福感到特别困惑。OP 是否在构建分布式负载均衡的电子商务系统?我的猜测是否定的;我将进一步假设序列化他的 $User 类或其他任何东西不会使他的服务器无法修复。我的建议:使用对您的应用程序敏感的技术。$_SESSION 中的对象很好,但须遵守常识性预防措施。如果您的应用程序突然变成在流量服务方面与亚马逊相媲美的东西,您将需要重新调整。这就是生活。

于 2012-02-05T15:39:38.090 回答
114

只要在调用 session_start() 时,PHP 已经遇到了类声明/定义,或者可以通过已安装的自动加载器找到,就可以了。否则它将无法从会话存储中反序列化对象。

于 2008-09-25T08:49:56.573 回答
35

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

更新:在 HTTP 级别没有会话的概念;服务器通过给客户端一个唯一的 ID 并告诉客户端在每次请求时重新提交它来提供这一点。然后服务器使用该 ID 作为 Session 对象的大哈希表的键。每当服务器收到请求时,它都会根据客户端随请求提交的 ID 从会话对象的哈希表中查找会话信息。所有这些额外的工作都是对可扩展性的双重打击(HTTP 是无状态的一个重要原因)。

  • Whammy One:它减少了单个服务器可以做的工作。
  • 重击之二:这使得扩展变得更加困难,因为现在您不能只将请求路由到任何旧服务器 - 它们并不都有相同的会话。您可以将具有给定会话 ID 的所有请求固定到同一服务器。这并不容易,而且是单点故障(不是针对整个系统,而是针对大部分用户)。或者,您可以在集群中的所有服务器之间共享会话存储,但现在您有更多的复杂性:网络附加内存、独立会话服务器等。

鉴于所有这些,您在会话中输入的信息越多,对性能的影响就越大(正如 Vinko 指出的那样)。正如 Vinko 指出的那样,如果您的对象不可序列化,则会话将行为不端。因此,根据经验,避免在会话中放置超过绝对必要的内容。

@Vinko您通常可以通过在您发回的响应中嵌入您正在跟踪的数据并让客户端重新提交它来解决服务器存储状态的问题,例如,将数据发送到隐藏的输入中。如果您真的需要服务器端状态跟踪,它可能应该在您的后备数据存储中。

(Vinko 补充说:PHP 可以使用数据库来存储会话信息,并且让客户端每次重新提交数据可能会解决潜在的可扩展性问题,但会带来一大堆安全问题,您必须注意现在客户端控制所有您的国家)

于 2008-09-25T08:51:51.280 回答
20
  • 无法序列化(或包含不可序列化成员)的对象不会像您期望的那样从 $_SESSION 中出来
  • 巨大的会话给服务器带来了负担(每次序列化和反序列化大量状态的成本很高)

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

于 2008-09-25T08:52:23.213 回答
11

以我的经验,对于比具有某些属性的 StdClass 更复杂的东西通常不值得。反序列化的成本一直高于在给定会话存储标识符的情况下从数据库重新创建。这看起来很酷,但(一如既往)分析是关键。

于 2008-09-25T09:03:43.593 回答
8

我建议不要使用 state ,除非你绝对需要它。如果您可以在不使用会话的情况下重建对象,请执行此操作。在您的 Web 应用程序中拥有状态会使应用程序的构建更加复杂,对于每个请求,您都必须查看用户处于什么状态。当然,有时您无法避免使用会话(例如:用户必须在会话期间保持登录状态)网络应用程序)。最后,我建议让您的会话对象尽可能小,因为它会影响序列化和反序列化大对象的性能。

于 2008-09-25T09:01:04.957 回答
4

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

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

于 2008-09-25T08:55:27.857 回答
1

我也会在升级软件库时提出——我们升级了我们的软件,旧版本的对象与 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.

于 2016-02-10T23:44:51.180 回答