【问题标题】:PHP: Standards of class constructors preventing instantiationPHP:防止实例化的类构造函数标准
【发布时间】:2010-11-30 05:54:43
【问题描述】:

只是一个关于标准的问题。

我为 PHP 会话管理创建了一个包装类,它有助于根据访问它的某些内部模块自动组织会话数据。它被设计为单例,使用getInstance() 方法进行实例化,因为在给定时间只会有一个会话。此外,这对我来说也是一个好处,因为我能够在session_start() 失败的情况下(尽管可能有限)防止会话对象的实例化。举个例子:

    public static function getInstance(){
        if(!self::$_instance || !session_id()){
            if(session_start()){
                self::$_instance = new self(session_id());
            }else{
                return;
            }

        }
        return self::$_instance;
    }

我的问题是;虽然使用网关getInstance() 方法在这里很自然地工作有几个原因,但是如果对象依赖于外部条件,在类中实现公共静态getInstance()create() 方法来控制对象创建是常见/好的做法吗?

我发现自己坚持一个约定,在单例的情况下提供getInstance(),在多个实例对象的情况下提供create()

TL;DR:我一直使用getInstance()create() 方法来控制所有对象实例化。我做错了吗?


编辑:稍微细化我的问题;除了将getInstance() 用于单例之外,我的构造函数是否使用create() 方法进行包装,目的更少,更倾向于不良约定?我应该从真正的构造函数中抛出异常,还是继续从 create() 返回 false?

【问题讨论】:

    标签: php design-patterns session singleton


    【解决方案1】:

    单身人士通常被认为是“坏的”;请参阅this section here 了解有关该主题的火焰战争。

    也就是说,使用工厂方法或工厂类来创建对象通常被认为是好的,所以你很好:)

    我个人使用symfony dependency injection 组件(可以在不使用 symfony 框架的情况下安装在任何项目中)来简化依赖注入并在看起来合适的地方避免单例。

    我仍然使用一些单例,这对我来说是有意义的;例如,记录器和工厂对象对我来说似乎很自然,所以我就这样制作它们。这个想法是全局功能(例如工厂)很好,但我相信全局状态不好。

    关于您修改的关于是否抛出异常或是否从您的 create() 调用中返回 false 的问题;这取决于您的应用程序是否可以在没有创建的对象的情况下继续成功。例如,如果您正在创建创建页面所必需的数据库连接,则抛出异常。如果您正在做一些不太重要的事情,请返回 false 并继续您愉快的方式:)

    【讨论】:

    • 单例模式还不错,这是肯定的。过度使用它是不好的(因为过度使用任何东西都是不好的)。 :)
    • 一切都要适度,我想:)
    • 谢谢El Yobo;我会看看你的建议:)
    • 进一步说明;我想通过将注册表设计为单例来全球化对象注册表将被认为与将打算与注册表一起使用的对象设计为单例一样“坏”(根据反单例阵营中的那些)。跨度>
    • 也许......但这就是我所做的。我想拥有一个单身比拥有许多要好:)
    【解决方案2】:

    getInstance() 在 Zend 框架中被广泛使用,这是我在代码中的标准和约定。

    至于create(),如何使用神奇的__construct 方法,以便在您执行new Blah() 时调用该类的__construct 方法?

    【讨论】:

    • 我将__construct 设置为私有(或在处理继承时受保护)和return new self($args); 来自create()
    • 所以@Tomcat,这不会创建您的对象的两个实例吗? $object1 = new Blah()。 $object2 = $object1->create();你的方法有什么优势?
    • 除了允许无实例方法链接 (Class::create()->method()->method();),没有。我对在同一范围内将 new 关键字与实例检索方法混合有一个奇怪的挂断。
    • 它封装了对象的构造。如果他稍后更改对象(例如从 Foo 到 Bar),他只需要更改工厂方法,而不是每次新的 Foo() 调用;这绝对是一件好事。在这种情况下,它实现了一个单例;这是否好是有待商榷的。
    【解决方案3】:

    您应该使用__construct 方法,然后使用create 方法。 由于 __construct 是自己调用的,因此您可以在构造函数中进行初始化和其他操作。 另一个好处是您可以忘记调用 create() 方法,并且您的对象可能处于不一致状态

    【讨论】:

    • 我不会忘记 :) 另外,我经常这样做; if($obj = Class::create()){,因此提供了实例化失败的条件,但也许这最好留给异常处理?
    • 工厂方法的重点是提供一种一致的方式来实例化对象,并在必要时轻松地允许您替换不同的对象。如果使用 $foo = new Bar(),那么如果要将所有 Bar 对象更改为 Blarg,则需要替换每个 new Bar() 语句。如果您使用工厂,则只需更换一个。所以,简而言之,你所做的已经很好了,不管 Shashwat。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多