PHP延迟静态绑定:类含被调用函数时self为何不存为最后非转发调用类名?
关于PHP延迟静态绑定中self不被记录为最后非转发调用类的原因
这问题问到点子上了!要搞懂这个,得先把「转发调用」「非转发调用」的本质,还有self和static的核心区别掰明白:
先明确两个关键概念
- 非转发调用:就是直接从外部发起的“源头级”调用,比如
B::foo()或者$b->foo(),这种调用会被PHP的延迟静态绑定(LSB)机制记录为「最后一次非转发调用的类」——这是LSB运行时绑定的核心依据。 - 转发调用:就是通过
parent::、static::或者forward_static_call()发起的调用,本质是把调用“转发”给继承链上的其他类;另外还有个特殊情况:如果当前类没定义某个方法,用self::调用时会回退到父类找,这时候self::也算转发调用。
再看self的本质:编译时绑定
self是编译阶段就固定死的静态绑定——不管运行时谁来调用,它指向的永远是写self关键字的那个类,和运行时的调用链完全无关。比如这个例子:
class ParentClass { public static function showClass() { echo "self指向:" . self::class . "\n"; echo "static指向:" . static::class . "\n"; } } class ChildClass extends ParentClass {} // 这里是直接调用ChildClass的showClass,属于非转发调用 ChildClass::showClass();
运行结果会是:
self指向:ParentClass static指向:ChildClass
这里ChildClass::showClass()是非转发调用,LSB记录的最后非转发类是ChildClass,所以static::class会输出ChildClass;但self::class在编译时就已经绑定到ParentClass了,不管调用者是谁,它都不会变。
回到你的问题:为什么self不会被保存为最后非转发类?
当类本身包含被调用的方法时,self::foo()的调用是直接执行当前类的方法,既不属于“转发调用”(因为没有把调用转给其他类),也不会产生新的“非转发调用”记录——因为非转发调用指的是外部发起的源头调用,而self::是类内部的静态绑定调用,它不参与LSB的运行时追踪逻辑。
简单说:LSB的“最后非转发调用类”是用来给static::这种运行时绑定用的,而self从一开始就走编译绑定,根本不依赖这个追踪机制,自然不会被保存为这个记录。
内容的提问来源于stack exchange,提问作者youhana
相关产品推荐
相关产品推荐

