【问题标题】:PHP: Storing 'objects' inside the $_SESSIONPHP:在 $_SESSION 中存储“对象”
【发布时间】:2010-09-13 00:43:17
【问题描述】:

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

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

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


编辑:

临时总结:现在我明白,即使涉及再次查询数据库,重新创建对象可能更好

进一步的答案可能在这方面详细说明更多!

【问题讨论】:

  • 我在 2008 年有多“愚蠢” :-)
  • 但对 2014 年像我们这样的“愚蠢者”有用的问题:D
  • 你向马库斯提出了非常好的问题.. :) 我今天读到了 ;)
  • 你不傻! 10 年后,你问我要问什么,并为我做的很扎实!
  • 好吧,我猜你只是让我免于在 2019 年问一个愚蠢的问题

标签: php session object


【解决方案1】:

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

【讨论】:

  • 谢谢!这为我修复了一个错误:D
  • 我假设如果你有一个合适的__autoload()函数,这个问题是可以避免的。
  • 在反序列化一个序列化对象时,我们是否必须添加类定义?在序列化对象时,它需要类定义,我同意,但是我是否还必须在必须取消序列化对象序列化的文件中添加类定义???
【解决方案2】:

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

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

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

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

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

(Vinko 补充说:PHP 可以使用数据库来存储会话信息,并且让客户端每次都重新提交数据可能会解决潜在的可伸缩性问题,但会带来很多您必须注意的安全问题,因为客户端在控制你的所有状态)

【讨论】:

  • HTTP 级别没有会话的概念;服务器通过给客户端一个唯一的 ID 并告诉客户端在每次请求时重新提交它来提供这一点。然后服务器使用该 ID 作为 Session 对象的大哈希表的键。待续……
  • 每当服务器收到请求时,它会根据客户端随请求提交的 ID 从会话对象的哈希表中查找会话信息。所有这些额外的工作都是对可扩展性的双重打击(HTTP 是无状态的一个重要原因)。待续……
  • 我想知道如果没有焊接状态,你将如何通过 HTTP 实现复杂的应用程序
  • 请编辑您的答案以包括所有这些 cmets。 wiki 更容易阅读和更好,无论如何,如果所有重要的东西都在 cmets 中,我不能选择你的答案作为接受的答案。谢谢!
  • "whammy one" 我希望我能多投反对票。知道你的时机。内存引用需要 100 纳秒或 0.0001 毫秒。因此,对存储在主内存中的哈希表进行查找实际上不会花费任何时间。 O(1) 有没有告诉你什么? @whammy 2:只是不要将所有请求随机路由到随机服务器?进行循环,并保持从同一用户路由到同一服务器。这是哇,超级明显。你必须回顾你的书,连同所有 30 多个赞成票
【解决方案3】:
  • 无法序列化(或包含不可序列化成员)的对象不会像您期望的那样从 $_SESSION 中出来
  • 巨大的会话给服务器带来了负担(每次序列化和反序列化大量状态的成本很高)

除此之外,我没有发现任何问题。

【讨论】:

    【解决方案4】:

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

    还要考虑会话的大小,具体取决于会话的存储方式、大小限制或延迟问题。

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 那么,重建对象是否更好,包括再次执行所有数据库查询?因为我这样做的一个想法是我不必再次查询数据库以获得相同的东西。
      • 如果它不会再次查询数据库对您很重要,请使用缓存而不是将其存储在会话中。但请在执行任何构建缓存之类的操作之前检查它是否真的会影响性能。
      • 谢谢,实际上我认为不是。我应该再次查询。
      【解决方案6】:

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

      【讨论】:

      • 对每次请求时查询 5x2 数据表与在会话中缓存结果并使用它之间的性能有何评论?
      【解决方案7】:

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

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

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

      【讨论】:

      • 很好的答案包含了我自己的很多想法,因为我一直在阅读这篇文章。现代互联网需要状态。虽然某些应用程序不需要状态并且以无状态方式进行有意义,但现代互联网依赖于太多基于状态的系统(AKA:登录!)只是放弃它们!多年来,互联网的大神们甚至将这个基本概念以 cookie 的形式纳入其中,并且在基本层面上,他们以 HTML 本地存储的形式添加了它。在 some 应用程序中避免过度使用状态可能是有意义的,但有些 != all!
      • 嗯,当我在人类发明火后不久问这个问题时,我不知道我今天知道的很多事情......这也很好。同时我会说可能有一些很好的用例,但通常我会先寻找其他解决方案。仍然将此标记为新接受的答案,因为另一个答案是分类的。
      • 很少有答案让我笑出声来。这个做到了。好极了 +1
      【解决方案8】:

      我也会在升级软件库时提出 - 我们升级了我们的软件,旧版本的对象与 V1 软件的类名在会话中,新软件在尝试构建会话中的对象时崩溃 -由于 V2 软件不再使用这些相同的类,所以它找不到它们。我们必须放入一些修复代码来检测会话对象,如果找到则删除会话,重新加载页面。最初最大的痛苦是当它第一次被报告时你正在重新创建这个错误(太熟悉了,“好吧,它对我有用”:) 因为它只影响最近进出新旧系统的人 - 但是,很好我们在发布之前确实找到了它,因为我们所有的用户肯定会在他们的会话中使用旧的会话变量,并且可能会导致所有人崩溃,这将是一个糟糕的发布:)

      无论如何,正如您在修改中建议的那样,我也认为最好重新创建对象。所以也许只是存储 id 然后在每个请求中从数据库中提取对象会更好/更安全。

      【讨论】:

        猜你喜欢
        • 2011-07-14
        • 2020-09-15
        • 1970-01-01
        • 2022-06-27
        • 2011-10-27
        • 1970-01-01
        • 1970-01-01
        • 2017-12-06
        相关资源
        最近更新 更多