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()

posted @ 2016-10-28 15:01  fly不起来啊!  阅读(270)  评论(0)    收藏  举报