You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:37:22