“延迟静态绑定”是 PHP5.3 之后的引进的概念,用来解决 PHP 面向对象中 self 关键词的“静态绑定”需要被“延迟”的问题。

首先来看一个大部分资料中经常引用的例子:

class A
{
    public static function echoClass()
    {
        echo __CLASS__;
    }

    public static function test()
    {
        self::echoClass();
    }
}

class B extends A
{
    public static function echoClass()
    {
        echo __CLASS__;
    }
}

B::test(); //输出A

按照大多数初学者的常规思维,既然类A中的 test 方法本质上是调用的自身的 echoClass 这个方法,echoClass 这个方法的作用是打印“自身”的类名称,类B既然继承自类A,自然也默认会继承类A中的 test 方法,那么调用类B中的 test 方法也应该打印类B自身的类名,但为什么最终的结果却反而是打印了类B的名称呢?

实际上,在 php 底层解析过程中,self 关键词是一个相对特殊的的地方,self 指向的是“定义” self 所在方法的类,而不是实际“调用” self 所在方法的类。听上去是比较枯燥,怎么理解这段话呢?就是说,php 语法解释器在解释执行 php 代码的时候,例子中类A的 self 关键词被解释器优先“绑定”到包含 self 所在方法的类A,后面无论什么时候调用 test 这个方法(即使是在继承类B中),self 关键词都是指代的是类A,所以 B::test() 其实等同于 A::test() ,代码输出的结果当然是 A 而不是 B 了。

在 php5.3 之前的版本中,self 关键词的静态绑定被添加了严格的限制,这样设计的目的现在已经无法得知,但为了让代码逻辑更加贴近现实,开发者们提出过许多笨拙的解决办法,直到5.3版本之后的 php 语法中,新关键字 static 的引入较好地解决了“延迟静态绑定”的问题,这里的 static 当然不再是简单地用来申明静态方法和属性的关键词,延迟静态绑定这一概念中的 static 被赋予了类似 self 关键词的含义,关键的是 static 指代的是在实际执行时候被调用的类,而不是包含 static 关键词的所在类,前面的例子可以改写为:

class A
{
    public static function echoClass()
    {
        echo __CLASS__;
    }

    public static function test()
    {
        static::echoClass();    // 利用static关键词延迟静态绑定
    }
}

class B extends A
{
    public static function echoClass()
    {
        echo __CLASS__;
    }
}

B::test(); //输出B