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

PHP中self::是否存在延迟绑定的特殊情况?

关于PHP延迟绑定中self::行为的疑问

PHP官方文档中关于延迟绑定(late static binding)的说明指出:self::会解析为编写该代码所在的类,例如在CurrentClass类中编写self::test(),等效于CurrentClass::test()。

但执行以下与文档示例类似的PHP代码:

<?php

class A
{
    // 返回延迟绑定的类名
    public static function meth(): string
    {
        return static::class;
    }
}

class B extends A
{
    public function check(): void
    {
        // 分别调用A、B、C的meth方法
        echo "A: ".A::meth()."\n";
        echo "B: ".B::meth()."\n";
        echo "C: ".C::meth()."\n";

        // 预期调用B的meth方法,输出B
        echo "self: ".self::meth()."\n";

        // 预期调用运行时类的meth方法,输出C
        echo "static: ".static::meth()."\n";

        // 预期调用B的meth方法,输出B
        echo "__CLASS__: ".(__CLASS__)::meth()."\n";
        echo "selfclass: ".(self::class)::meth()."\n";

        // 预期调用运行时类的meth方法,输出C
        echo "staticclass: ".(static::class)::meth()."\n";
    }
}

// C继承B,未重写check方法
class C extends B {}

(new C)->check();

在PHP 8.1.2中运行后输出:

A: A
B: B
C: C
self: C
static: C
__CLASS__: B
selfclass: B
staticclass: C

其中self: C的输出不符合预期——按照文档描述,self::meth()应该等效于B::meth(),输出B,但实际输出了C。这是Bug、特殊特性,还是对文档的理解有误?


解答

这不是Bug,是对self::和延迟绑定的理解偏差:

  • self::确实指向定义该代码的类(这里是B),但self::meth()并没有调用B类自己的meth方法——因为B没有重写meth,这个方法是从A继承来的。
  • A类的meth方法返回的是static::class,这里的static::是延迟绑定标记,它的指向取决于运行时的调用上下文:当通过C的实例调用check方法时,整个调用的运行时类是C,所以A中static::class最终指向C,导致输出C。

再对比其他几个调用的差异:

  • (__CLASS__)::meth()和self::class::meth():__CLASS__和self::class都是字符串"B",相当于显式调用B::meth(),此时A中static::class的上下文是B,所以输出B。
  • static::meth():static::直接指向运行时类C,调用后A中static::class自然指向C,输出C。

内容的提问来源于stack exchange,提问作者Džuris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:57:22