【问题标题】:Are PHP singleton classes somehow shared between requests?PHP单例类是否在请求之间以某种方式共享?
【发布时间】:2009-01-11 02:13:44
【问题描述】:

我在所有 PHP 类文件中都使用单例模式。

是否会导致用户在网站上的操作与其他用户的操作发生冲突?

例如,当应用程序上线并且我们同时在站点上有多个用户时,执行类似的操作从而调用相同的 PHP 类(在幕后),因为单例阻止了一个类的多个实例并且只返回单个实例。

例如我有一个名为 Search.php 的类,它是一个单例类。此类处理来自网站的所有搜索查询。如果多个用户同时在网站上执行搜索,他们的操作是否会相互冲突,因为它只是可以创建的 Search 类的单个实例。

非常感谢您的宝贵时间。

【问题讨论】:

  • 一般当你有这样的“假设”问题时,你应该假设它是不正确的,除非另有证明。如果您甚至不得不在这里询问并且不能自己运行并验证它是否正确,那么您的构建中存在一些需要排除的深层缺陷。要求代码向您证明它符合预期的工作不应该是一项痛苦的工作,如果是这样,您会遇到更大的问题,这些问题将持续存在成百上千个看似无关的微小问题,直到您解决根本问题。
  • 在我自己看来,很少有任何情况需要单身。使用它们作为一种通用方法将使您的代码既不可测试又不可扩展,并且会使您的生命周期结束日期明显提前。但是,我也不同意单身人士从来没有正当理由的心态。 99% 的时候,没有理由,这表明要么是懒惰,要么是计划不周。剩下的 1% 的时间是在完成其预期的工作并且不应该改变,不管有多少人抱怨他们。
  • 通常应该认识到,使用不当的单例几乎总是对自己造成的问题的回应。当“我没有创建另一个实例”提供相同的解决方案而没有限制时,没有理由说“不能创建另一个实例”。例如,单例的有效使用是创建一个原型器,它需要维护一个要克隆的空白实例化实例,然后通过构造函数以外的方法手动初始化该实例。那真的是我唯一一次使用它们,但我确实一直在使用它们。
  • 在上面的例子中,还应该说明实际的原型机不是单例的。只有它产生的空白模板基线对象实例是。原型机本身可以重置或创建为另一个并行实例,并在过程中发布/更新/接收完全不相关的基线集作为情况保证。

标签: php class singleton


【解决方案1】:

简短的回答是否定的。

每个页面请求都作为一个唯一的实例进行处理,唯一将每个用户的请求联系在一起的是会话 cookie。试着把 PHP 想象成一个应用程序,它在你调用脚本时启动,在脚本完成时终止。它不维护任何状态,也不知道任何其他 PHP 实例。

单例模式只是您设计类的一种方式,您可以在代码中的任何位置(如全局)调用它,而不必关心它是否已经被实例化并且您希望它持续存在在内存中。

【讨论】:

    【解决方案2】:

    每个请求都是自包含的,不会与其他请求共享数据(除非您为此使用特定的扩展,例如 memcache)。因此,在您的应用程序中使用单例不会影响来自不同用户的单独请求。

    你应该关心的是你对单例模式的过度使用。单例是全局的 OO 版本,如果您不小心,可能会导致一些奇怪的错误。最好使用不依赖全局设置的作用域操作,并谨慎使用单例。

    【讨论】:

    • 那么它的明显缺点是什么?
    • 正如我所说的与全局相同 - 通过依赖可以从应用程序中的任何位置设置的信息,您不知道最后发生了什么变化。可能导致不可预知的结果。
    • 您可以尝试使用 Zend_Registry 之类的方法来存储对象/值,而不是将许多类变成单例。自己实现类似的东西应该很容易,或者只使用该代码。 framework.zend.com/manual/en/zend.registry.html
    【解决方案3】:

    单例模式是比较有争议的模式之一。批评者认为,单例将全局状态引入应用程序,并将单例及其消费类紧密耦合。这会导致隐藏的依赖关系和意想不到的副作用,进而导致代码更难测试和维护。

    批评者进一步认为,在 PHP 这样的无共享架构中使用单例是没有意义的,因为无论如何,对象在请求中都是唯一的。通过在请求开始时使用 Builders 和 Factory 模式来创建协作者对象图更加容易和清晰。

    单例也违反了几个“SOLID”OOP 设计原则和得墨忒耳定律。单例不能序列化。它们不能被子类型化(在 PHP 5.3 之前)并且不会被垃圾收集,因为实例被存储为 Singleton 的静态属性。

    【讨论】:

      【解决方案4】:

      我同意,答案是否定的。我现在正在考虑 PHP 中的单例模式,并决定虽然单例模式可以用 PHP 编码,但它并没有真正实现,因为实例没有跨请求共享(或存储在进程内存中,就是这种情况对于像 ASP.net、Java 和 Ruby on Rails 这样的 Web 服务器环境?)您可以序列化 Singleton 实例并将其存储在会话中,但仍然不能跨会话共享。我推测它必须存储在缓存中才能在 PHP 中完全实现单例模式。但我还没有这样做,所以我不确定。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-06-16
        • 1970-01-01
        • 2015-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-11
        相关资源
        最近更新 更多