<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
/*A::foo();
A::foo();
B::foo();*/
A::foo();
parent::foo();
self::foo();
}
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
// 当有parent和self前缀时,可以考虑换成具体的类名进行思考
// 如果函数的内容是static前缀,则要考虑最后一次“非转发调用”的类名
// 当有parent和self前缀时,如此例,只需要考虑调用这个函数的类就可以了,在这里是C::test()
class C extends B {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
// A C C
- 转发调用: 进行静态调用时前面有static修饰的
- 非转发调用: 直接通过类名,方法名调用的
- 后期静态绑定工作原理是存储了在上一个“非转发调用”(non-forwarding call)中的类名
- 意思是当我们调用一个转发调用的静态调用时,实际调用的类是上一个非转发调用的类。
- 分析一下上面的例子
- Class C的test方法中的三个方法,它们的非转发调用类都是C,因为它是直接通过C::test()方式访问的
- A::foo() 非转发调用 方法内部又进行了转发调用,这时的上一个非转发调用的类是A,所以输出A
- parent::foo() 调用了Class B的foo方法,该方法内进行了一次转发调用,这时的上一个非转发调用的类是C,所以输出C
- self::foo() 调用了自身的foo方法,该方法内也进行了一次转发调用,道理同上,所以输出C
- 可以尝试将Class C foo方法中的static::who()分别替换成self::who(), parent:who() 看看效果,前者输出C 后者输出B