类的后期静态绑定

概念

自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定(Late Static Binding)的功能,用于在继承范围内引用静态调用的类
它的工作原理是:

存贮了上一个“非转发调用”(non-forwarding call)的类名
进行静态方法调用时,该类名即为明确指定那个。(在::运算符左侧那个)
进行非静态方法调用时,即为该对象所属的类名。

理解

读到这里的时候,就有一个新的概念,“非转发调用”(non-forwarding call) 和 “转发调用”(forwarding call)
那么什么是转发调用呢?是指通过以下几种静态方式调用:

  1. self::
  2. parent::
  3. static::
  4. forward_static_call()方法

那么对应的非转发调用就是如下调用方式:

  1. Foo::method() // 类名::方法
  2. $obj->method() // 对象->方法

那么就很好理解了,后期静态绑定就是保存了上面的Foo类 或 $obj对象所在的类。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class A
{
public static function foo()
{
static::who();
}
public static function who()
{
echo __CLASS__ . "<br>";
}
}
class B extends A
{
public static function test()
{
A::foo();
parent::foo();
self::foo();
}
public static function who()
{
echo __CLASS__ . "<br>";
}
}
class C extends B
{
public static function who()
{
echo __CLASS__."<br>";
}
}
C::test(); // A C C

对于这里的理解,首先,C里面没有test()这个方法,直接进入到B去寻找,然后看B的test方法第一个A::foo(),这里直接使用了非转发调用,那么打印A是毫无疑问的。然后parent::foo()是转发调用,转的谁的呢?往上一步走,就是C::test(),所以转发的是C这个类,但是这里注意一点,必须保证C类有who方法才行,同理,第三行的self::foo()也是转发调用,同样回溯到C::test()这里的非转发调用来,那么它也是C。
那么同样的,对于上面的类,如果这样调用的话:

1
2
A::test();// A A A
B::test(); //A B B

所以,只需要记住这点:存贮了上一个“非转发调用”(non-forwarding call)的类名就很好理解了。