static 和 self 区别
1,在 PHP 中,我们可以使用 new static() 结合私有构造函数和一个静态方法来实现单例模式。以下是一个简单的例子
class Singleton { // 私有化构造函数,防止外部直接实例化 private function __construct() {} // 静态变量用于存储单一实例 private static $instance; // 使用 new static() 创建并返回单例对象的公共静态方法 public static function getInstance(): self { if (null === static::$instance) { static::$instance = new static(); } return static::$instance; } // 防止克隆 private function __clone() {} // 示例:类中的一个简单方法 public function doSomething() { echo 'Singleton is working.'; } } // 获取 Singleton 类的单例对象 $singleton1 = Singleton::getInstance(); $singleton1->doSomething(); // 再次获取同一个实例 $singleton2 = Singleton::getInstance(); // 因为是单例,所以 $singleton1 和 $singleton2 实际上指向的是同一对象
在这个例子中,getInstance() 方法使用 new static() 来创建并返回类的唯一实例。由于构造函数是私有的,因此无法通过其他方式实例化这个类。这样就确保了在整个应用程序中,无论何时调用 getInstance() 方法,都只会返回同一个实例,从而实现了单例模式。
在 PHP 中,new static() 和 new self() 都是用来创建对象的表达式,但它们之间存在一定的区别:
1. new self(): - self 关键字指向当前类,无论是在哪个类中调用,它始终指向定义该方法的类。 - 当你在某个类的方法中使用 new self() 时,它会创建该类的一个新实例。
2. new static(): - static 关键字指向的是实际运行时的类,也就是说,在继承层次结构中,如果子类重写了父类的方法并在这个方法内部使用 new static(),那么它将创建
的是当前上下文中的类(即子类)的实例,而不是父类的实例。 - 这种动态绑定的行为使得 new static() 在处理继承关系时更加灵活,特别是在工厂方法、单例模式或者构造函数等需要创建当前类实例的场景下非常有用。
总结一下:
- 如果你希望总是创建当前类的新实例,而不考虑继承和覆盖的情况,使用 new self()。
- 如果你希望根据实际调用类来创建相应类的新实例(即支持多态性),尤其是在面向对象设计中处理继承关系时,应使用 new static()。
<?php class Father { // 父类中的 say 方法 public function say() { return 'PHP'; } // 父类中的静态 demo 方法 public static function demo() { $obj = new static(); // 猜想一下,应该调用哪个 say 方法呢? return $obj->say(); } } class Sub extends Father { // 子类中的 say 方法 public function say() { return 'ThinkPHP5'; } } // 调用父类的静态 demo 方法 echo Father::demo(); // 返回: PHP // 调用子类的静态 demo 方法,实际会调用子类重写的 say 方法 echo Sub::demo(); // 返回: ThinkPHP5
在上述代码中,Father::demo() 和 Sub::demo() 都是调用静态方法。
在 demo 方法内部使用了 new static() 创建对象,
由于 static 关键字指向调用该静态方法的类,
因此: - 当调用 Father::demo() 时,new static() 实际创建的是 Father 类的对象,
所以调用的是父类的 say 方法。 - 当调用 Sub::demo() 时,new static() 实际创建的是 Sub 类的对象,所以调用的是子类重写的 say 方法