新的self()是什么?在PHP中意味着什么?


110

我从未见过这样的代码:

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

一样new className()吗?

编辑

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



@stereofrog,您是说应该放弃单例模式吗?但是所有事物存在都是有原因的,对吧?
user198729 2010年

哦,我倾向于同意这一点:应该用工厂代替单例
user198729 2010年

@stereofrog Singleton是单元测试的毒药,要对从一个调用更改为另一个调用的状态进行不可变的测试非常困难。
大卫

不幸的是,这种方法不会扩展。它将始终为您定义该函数的类提供一个新对象。
阿瑞斯

Answers:


211

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) { } 

意思selfMyChildClass-即编写它的类。


对于第二种情况,代码如下所示:

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 <5.3,“编写该类的类”很重要-有时会引起问题。

这就是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 Late Bindings页面。


@Paul:heu ...的意思是“自我充当别名”或“自我指向” –法语中的“ designer”动词可用于此目的–我想是这种情况之一在其中使用相同的单词不是一个好主意;-(我将编辑我的答案以解决此问题;;谢谢:-)
Pascal MARTIN 2010年

如果有baseclassclass它指向哪一个呢?
user198729 2010年

@user:我已经编辑了答案,以提供有关self继承的更多信息;并且我还包括了有关staticPHP 5.3的一些信息;希望这会有所帮助:-)
Pascal MARTIN

10

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

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

如果调用,则每次调用className::getInstance()都会得到一个相同的类实例,这就是单例模式的关键所在。

不过,我从未见过如此做过,老实说,我不知道这是有可能的。什么是$_instance声明为类?


1
$_instance声明为public static $_instance;
Atif,2014年

7

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

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

private static $_instance = NULL; 

在正常的课堂上,我们可以通过简单地访问该成员

$this->_instance = 'something';

但是它声明为static,所以我们不能使用$ this代码来代替

self::$_instance

通过检查此静态类变量上是否存储有对象,类可以决定创建还是不创建单个实例,因此,如果未设置该实例,则为isisset,这意味着静态成员$ _instance上不存在任何对象,则它生成一个新对象,并$_instance通过命令将其存储在静态成员中

self::$_instance = new self();

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

$thisObject = className::getInstance();

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


2

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


为什么有人在PHP中使用Singleton模式?除非在类似守护程序的程序中使用,否则单例将仅在脚本运行时存在,然后与程序一起消失。
ILikeTacos

4
避免恼人地声明全局变量访问全局变量
Sam Adamsh 2014年

0

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.