理解 PHP 延迟静态绑定 (late static bindings)

简单理解PHP延迟静态绑定

static::中的static其实是运行时所在类的别名,并不是定义类时所在的那个类名。这个东西可以实现在父类中能够调用子类的方法和属性。

使用(static)关键字来表示这个别名,和静态方法,静态类没有半毛钱的关系,static::不仅支持静态类,还支持对象(动态类)。

预备概念

转发调用

所谓的“转发调用”(forwarding call)指的是通过以下几种方式进行的静态调用:self::,parent::,static:: 以及 forward_static_call()。

非转发调用

那么非转发调用其实就是明确指定类名的静态调用(foo::bar())和非静态调用($foo->bar())

后期静态绑定原理

后期静态绑定工作原理是存储了在上一个“非转发调用”(non-forwarding call)的类名。

例子1,简单使用static::

class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // 后期静态绑定从这里开始
    }
}
class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}
B::test();

以上例程会输出:

B

例子2,区分转发调用和非转发调用

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

以上例程会输出:

A
C
C

例子3,使用场景举例

class Model 
{ 
    public static function find() 
    { 
        echo static::$name; 
    } 
} 

class Product extends Model 
{ 
    protected static $name = 'Product'; 
} 

Product::find(); 

参考资料:

PHP官方的解释

本帖已被设为精华帖!
本帖由 Summer 于 7年前 加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 12

例子1的结果应该是B吧,我在php7上跑了下也是B:smile:

7年前 评论

例子1的结果应该是B吧,我在php7上跑了下也是B:smile:

7年前 评论

1楼正解,的确是 B
如果是 self::who(), 才是 A

7年前 评论

对啊 ,差点都怀疑自己

7年前 评论

@jiyis 这个脸打得。。。。写完文章的没细看。。的确是B,已修正,谢谢

7年前 评论

@CRQM :laughing: 没有没有,文章写的好了才会让人仔细看!

7年前 评论

@jiyis 真是客气,社区氛围好!

7年前 评论

:+1: 很详细,便于记忆+理解

7年前 评论

学习了

4年前 评论
learner

例子2,parent::foo();为什么输出C?不甚明白,望高人指点迷津!

4年前 评论
kakaxi 3年前
learner

@garguntua 例子 2,parent::foo (); 为什么输出 C?

4年前 评论
learner

@Hanson 例子 2,parent::foo (); 为什么输出 C?

4年前 评论

@learner

所谓的“转发调用”(forwarding call)指的是通过以下几种方式进行的静态调用:self::,parent::,static:: 以及 forward_static_call()。

后期静态绑定工作原理是存储了在上一个“非转发调用”(non-forwarding call)的类名。

个人理解:

  1. C::test();中 ,这是调用明确指定类名的静态方法,属于“非转发调用”,这个“非转发调用”的类名C被存储下来。
  2. parent::foo();属于转发调用,记录的最后一个”非转发调用“ 的类名不变,依然是C。
  3. static::who();这个语句用到了static::,也就是“后期静态绑定”。再看一下定义:

    “后期绑定”的意思是说,static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。

而这个实时计算出来的类,按照工作原理,就是我们一直存储着的C。

  1. 结论就是,test()中的第二句,相当于在直接调用C::who();。显然输出结果是C。
4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!