PHP static 延迟静态绑定
首先看这种写法
1 <?php 2 abstract class A 3 { 4 public static function create(): A 5 { 6 return new self(); 7 } 8 } 9 class B extends A 10 { 11 } 12 B::create();
会成功实例化B吗?不会的,并且还会报错
Error: Cannot instantiate abstract class A in D:\wamp64\www\test.php on line 6
实际上,self对该类的作用与$this对对象的作用不完全相同。self不是指调用上下文,而是指解析上下文。因此,如果运行上面的例子,会报错,无法实例化抽象类
也就是说,self指向了定义了create()方法的A抽象类,而不是发送调用的B。在PHP5.3之前,这都是一种严格的限制,也出现了许多笨拙的解决方法。PHP5.3中引入了一种叫做延迟静态绑定的概念,最明显的特征就是关键字static。static与self类似,区别在于前者引用的是被调用的类。
这样写就能在静态上下文中利用继承关系了:
1 <?php 2 abstract class A 3 { 4 public static function create(): A 5 { 6 return new static(); 7 } 8 } 9 class B extends A 10 { 11 } 12 B::create();
2.
static关键字的用处可不止实例化而已。和self、parent一样,static还可以被用作静态方法调用的标识符,在非静态上下文中也一样。看代码:
A类中有分类group的概念,默认情况下是”default“类,我也可以在类的继承层次的分支中改变这个类别
1 abstract class A 2 { 3 private $group; 4 public function __construct() 5 { 6 $this->group = static::getGroup(); 7 } 8 public static function create(): A 9 { 10 return new static(); 11 } 12 public static function getGroup() 13 { 14 return 'default'; 15 } 16 } 17 18 class B extends A 19 { 20 } 21 22 class C extends A 23 { 24 public static function getGroup() 25 { 26 return 'document'; 27 } 28 } 29 30 class D extends C 31 { 32 } 33 var_dump(B::create(), C::create(), D::create());
我在A类中加入了一个构造方法,他会使用static关键字调用静态方法getGroup()。A类提供了“default”类别的实现。另外我还创建了一个新的类D,它继承自C。上面例子的输出结果为:
D:\wamp64\www\test.php:34:
object(B)[1] private 'group'
(A)
=>
string
'default' (length=7)
D:\wamp64\www\test.php:34:
object(C)[2] private 'group'
(A)
=>
string
'document' (length=8)
D:\wamp64\www\test.php:35:
object(D)[1] private 'group'
(A)
=>
string
'document' (length=8)
对于D类,会先从被调用的D类自身开始找。由于它没有提供实现,C类中的getGroup()方法会被调用。
注意,假如把A类中 return new static() 改为 return new self(),那结果可就不一样了,就都会变成default了,因为使用self关键字的话,只有在实例化A(而不是D)时才能找到getGroup()