120

我从未见过这样的代码:

public static function getInstance()
{
    if ( ! isset(self::$_instance)) {
        self::$_instance = new self();
    }
    return self::$_instance;
}

是一样的new className()吗?

编辑

如果类是继承的,它指向哪个类?

4

5 回答 5

229

self指向编写它的类。

因此,如果您的 getInstance 方法在类名MyClass中,则以下行:

self::$_instance = new self();

会做同样的事情:

self::$_instance = new MyClass();


编辑:评论后提供更多信息。

如果您有两个相互扩展的类,则有两种情况:

  • getInstance在子类中定义
  • getInstance在父类中定义

第一种情况看起来像这样(对于这个例子,我已经删除了所有不必要的代码——你必须将它添加回来才能获得单例行为)*:

class MyParentClass {
    
}
class MyChildClass extends MyParentClass {
    public static function getInstance() {
        return new self();
    }
}

$a = MyChildClass::getInstance();
var_dump($a);

在这里,您将获得:

object(MyChildClass)#1 (0) { } 

这意味着self意味着MyChildClass- 即编写它的类。


对于第二种情况,代码如下所示:
class MyParentClass {
    public static function getInstance() {
        return new self();
    }
}
class MyChildClass extends MyParentClass {
    
}

$a = MyChildClass::getInstance();
var_dump($a);

你会得到这种输出:

object(MyParentClass)#1 (0) { }

这意味着self意味着MyParentClass- 也就是在这里,它被写入的类




使用 PHP 这就是 PHP 5.3 为static关键字引入新用法的原因:它现在可以准确地用于我们self在这些示例中使用的位置:

class MyParentClass {
    public static function getInstance() {
        return new static();
    }
}
class MyChildClass extends MyParentClass {
    
}

$a = MyChildClass::getInstance();
var_dump($a);

但是,使用static而不是self,您现在将得到:

object(MyChildClass)#1 (0) { } 

这意味着static那种指向使用的类(我们使用MyChildClass::getInstance()),而不是编写它的类。

当然,行为self并没有改变,为了不破坏现有的应用程序——PHP 5.3 只是添加了一个新的行为,循环使用static关键字。


而且,谈到 PHP 5.3,您可能需要查看 PHP 手册的 [Late Static Bindings][1] 页面。
于 2010-03-07T13:41:32.213 回答
10

这似乎是单例模式的实现。该函数被静态调用并检查静态类是否$_instance设置了变量。

如果不是,它会初始化自身的一个实例 ( new self()) 并将其存储在$_instance.

如果您调用className::getInstance(),您将在每次调用时获得一个相同的类实例,这就是单例模式的要点。

不过,我从来没有见过这样做的,老实说,我不知道这是可能的。类中声明的内容是什么$_instance

于 2010-03-07T13:41:59.017 回答
7

这很可能用在单例设计模式中,其中构造函数被定义为私有以避免被实例化,双冒号(::)运算符可以访问类内部声明为静态的成员,因此如果有静态成员,则伪变量$这不能使用,因此代码使用 self 代替,单例是很好的编程实践,它只允许一个对象的实例,如数据库连接器处理程序。从客户端代码中,访问该实例将通过创建单个访问点来完成,在这种情况下,他将其命名为getInstance()getInstance 本身就是创建对象的函数,基本上使用 new 关键字创建对象,这意味着构造方法是也被称为。

该行if(!isset(self::instance))检查是否已经创建了一个对象,您无法理解这一点,因为代码只是一个片段,在顶部的某个地方,应该有像可能这样的静态成员

private static $_instance = NULL; 

在普通类中,我们可以通过简单地访问该成员

$this->_instance = 'something';

但是它声明为静态的,所以我们不能使用我们使用的 $this 代码

self::$_instance

通过检查这个静态类变量上是否存储了一个对象,该类可以决定创建或不创建单个实例,所以如果它没有设置,!isset,意味着静态成员 $_instance 上不存在对象,然后它生成一个新对象,$_instance通过命令将其存储在静态成员中

self::$_instance = new self();

并将其返回给客户端代码。然后客户端代码可以愉快地使用对象的单个实例及其公共方法,但是在客户端代码中,调用单个访问点,即getInstance()方法也很棘手,必须这样调用

$thisObject = className::getInstance();

原因是函数本身被声明为静态的。

于 2010-11-25T05:25:34.263 回答
2

是的,它就像new className()(指包含该方法的类),可能在构造函数是私有的单例模式中使用。

于 2010-03-07T13:41:40.840 回答
0

如果类是继承的,那么从 child 调用 getInstance() 不会给你一个 child 的实例。它只会返回父实例的一个实例。这是因为我们调用了 new self()。

如果您希望子类返回子类的实例,则在 getInstance() 中使用 new static(),然后它将返回子类实例。这叫做后期绑定!!

于 2015-09-27T07:20:12.960 回答