在PHP中,new self();是什么意思?

126

我从未见过这样的代码:

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

它和 new className() 是一样的吗?

编辑

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


1
https://dev59.com/DXVC5IYBdhLWcg3w51hv - meder omuraliev
@stereofrog,你的意思是单例模式应该被废弃吗?但是所有事情都有存在的理由,不是吗? - user198729
哦,我倾向于同意这个观点:单例应该被工厂替代。 - user198729
@stereofrog 单例模式对单元测试来说是有害的,因为很难在每次调用时都保持状态不变,从而使得测试变得不可变。 - David
不幸的是,这种方法无法扩展。它总是会给你一个新的对象,该对象来自定义此函数的类。 - Ares
5个回答

243

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手册的[后期静态绑定][1]页面。

@Paul:嗯...意思是“self充当别名”,或者“self有点指向”-- 在法语中,“designer”动词可以用于这个意思 -- 我想这就是在英语中使用相同单词不是一个好主意的情况之一;-(我会编辑我的答案来修正这个问题;;谢谢 :-) - Pascal MARTIN
如果存在baseclassclass,它指向哪一个? - user198729
@user:我已经编辑了我的回答,关于self和继承,我提供了更多的信息;而且我还包括了一些有关PHP 5.3中的static的信息;;希望这可以帮助你 :-) - Pascal MARTIN

10

这似乎是 单例模式 的实现。

该函数以静态方式调用并检查静态类是否设置了变量 $_instance

如果没有设置,则初始化自身的一个实例 (new self()) 并将其存储在 $_instance 中。

如果您调用 className::getInstance(),则在每次调用时都会获得 同一个 类实例,这是单例模式的目的。

我从未见过这样做,而且老实说我不知道这是可能的。 在类中,$_instance 声明为什么?


1
$_instance is declared as public static $_instance; - Atif

7
这段代码很可能用于单例设计模式中,其中构造函数被定义为私有以避免实例化,双冒号(::)操作符可以访问类内声明为静态的成员,因此如果存在静态成员,则伪变量$this不能使用,因此代码使用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();

这个函数在本质上被声明为静态的。


3

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


为什么有人会在PHP中使用Singleton模式?除非在类似守护程序的程序中使用,否则Singleton只会在脚本运行时存在,然后随着程序的消失而消失。 - ILikeTacos
4
避免烦人地声明全局变量以访问全局变量。 - Sam Adamsh

0
如果类被继承,那么从子类调用getInstance()将不会给你一个子类的实例。它只会返回一个父类实例。这是因为我们调用了new self()。
如果你想让子类返回一个子类实例,那么在getInstance()中使用new static(),它将返回子类实例。这就是所谓的后期绑定!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接