self:: 编译期绑定,始终指向定义处的类;static:: 运行时绑定,指向实际调用者类。二者在继承中重写静态属性、实例化、方法调用时行为不同,parent:: 则专用于显式调用父类成员。

static:: 和 self:: 在继承中访问静态属性时行为完全不同
子类未重定义同名静态属性时,self:: 和 static:: 都读取父类的值;但一旦子类声明了同名静态属性,self:: 仍死锁在父类定义处,static:: 才会转向子类副本。
常见错误现象:父类有个 $config,子类覆盖后用 self::$config 读取,结果还是父类值,配置没生效。
-
self::$config永远指向写该行代码的那个类(编译期绑定) -
static::$config运行时查调用链末端类,子类调用就找子类 - 若子类没声明
$config,两者都读父类 —— 此时看似一样,但本质不同
new self() 和 new static() 实例化结果不一致
在父类的实例方法或静态方法里,new self() 总是返回父类实例,而 new static() 返回实际调用者所属类的实例。这是工厂模式、单例基类必须区分的关键点。
使用场景:你写了一个基类 Repository,希望子类 UserRepository 调用 create() 时返回 UserRepository 实例,而不是 Repository。
立即学习“PHP免费学习笔记(深入)”;
-
new self()等价于硬编码new ParentClass() -
new static()等价于运行时解析的new CalledClass() - PHP 5.3+ 才支持
new static();低于此版本会报错或退化为new self()
静态方法中调用同名方法时,self:: 不支持多态,static:: 支持
父类定义一个静态方法 who(),内部用 self::name(),子类重写 name() 后调用 who(),结果仍是父类的 name() —— 因为 self:: 绑定在父类代码里。换成 static::name(),才真正调用子类版本。
容易踩的坑:你在基类里写了通用的 getInstance(),但子类单例始终拿不到自己的 $instance,就是因为用了 self::$instance。
-
self::name()是早期绑定,方法体在哪定义就去哪找 -
static::name()是后期静态绑定(Late Static Binding),运行时从调用起点向下查 - PHP 8.0 完全支持,无需额外配置;但注意命名空间下需完整引用或 use 别名
parent:: 是另一条路,和 self/static 无替代关系
parent:: 明确指定向上调用父类成员,和 self::(当前定义类)、static::(当前调用类)三者语义正交。混淆它们是新手常见问题。
典型误用:想在子类 setUp() 里复用父类逻辑,却写 self::setUp(),结果递归调自己崩栈;正确做法是 parent::setUp()。
-
parent::method()只能用于继承链中显式向上跳一级 -
self::method()锁死在当前类(哪怕在子类里调用) -
static::method()往下找最末端实现,不关心中间层级
self 和 static 表现一致,容易让人误以为可互换 —— 但只要项目开始扩展子类,bug 就立刻浮现。



















