php后期静态绑定
转载自https://my.oschina.net/u/929017/blog/680612
摘要: php后期静态绑定解惑
* 文中用lsb代表Late Static Bindings。
关于lsb的官方文档http://php.net/manual/en/language.oop5.late-static-bindings.php
之前在看laravel源码的时候,看到一个陌生的static用法:static::foobar(),查了下是个叫做后期静态绑定的东西,看官方文档老是看不懂,今天又想起这个事,终于把它搞懂了。
More precisely, late static bindings work by storing
the class named in the last "non-forwarding call".
关键就在这句,实现lsb的关键在于“存储了上一次非转发调用的类名”,什么是非转发调用?先看官方定义的转发调用是什么:
所谓的“转发调用”(forwarding call)指的是通过以下
几种方式进行的静态调用:self::,parent::,static:: 以及 forward_static_call()。
关键词:静态调用、self::、parent::、static::、forward_static_call()。在进行静态调用时未指名类名则是转发调用。
对应的非转发调用就是明确指定类名的静态调用和非静态调用($foobar->foobar()调用形式)。
转发与非转发调用本质区别在于是否将调用者的信息传递下去。这个概念只有在使用lsb的时候才有意义。
明白了什么是转发与非转发调用就基本上明白lsb了。以官方文档给的例子
<?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();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
首先C::test(),进入test方法,A::foo()、parent::foo()、self::foo()这三个方法调用的“上一次
非转发调用”存储的类名就是C啦。
通过A::foo()进入foo方法时,“上一次非转发调用”存储的类名就变成A啦。所以static::实际上代表A::。
通过parent::foo()进入foo方法时,“上一次非转发调用”存储的类名还是C。所以static::代表C::。
通过self::foo()进入foo方法时,“上一次非转发调用”存储的类名还是C。所以static::代表C::。
注意这里之所以会触发lsb是因为foo()方法中的static::用法。如果这里的static::who()改为self::who(),则不会出lsb,也就没有“上一次非转发调用”存储的类名这个概念了,实际上就是A::who()

浙公网安备 33010602011771号