应使用 static:: 而非 self:: 实现动态静态绑定;trait 同名方法需用 use + as/insteadof 显式处理;parentclass::foo() 编译期绑定父类,static::foo() 才支持运行时子类解析。

静态方法调用写 self:: 还是 static::?
写 self:: 就锁死在当前类,哪怕子类调用也执行父类里的版本;写 static:: 才会按“谁发起调用”动态找对应类的方法体。这是绝大多数静态工厂、单例、配置加载逻辑翻车的根源。
- 父类里写
self::make()→ 永远返回父类实例,子类继承后也一样 - 父类里写
static::make()→B::make()返回B实例,C::make()返回C实例 - 如果方法里还要调用本类另一个静态方法,别想当然用
self::,先确认是否需要被子类覆盖
Trait 和类同名静态方法冲突怎么破?
PHP 默认不让共存:哪怕一个是 public static,一个是 protected static,只要名字一样,就会报 Fatal error: Trait method xxx has not been applied。不能靠访问控制符“躲过去”,必须显式处理。
- 用
use TraitName { TraitName::methodName as aliasName; }给 Trait 方法起别名 - 别名后,类自己的方法照常调用,Trait 的方法走别名,两者互不干扰
- 别名可同步改可见性:
TraitName::methodName as public bootMediable
多个 Trait 同时定义了 log(),该用哪个?
PHP 不猜,直接报错中断。你得告诉它“谁优先”“谁让路”“谁改名”。没有默认策略,也没有隐式合并。
- 用
insteadof指定主用版本:TraitA::log insteadof TraitB - 被排除的版本别丢,用
as保留:TraitB::log as logToDb - 注意顺序:
use TraitA, TraitB { ... }中,insteadof只能针对已列出的 Trait,不能跨未声明的
为什么 ParentClass::foo() 总是调父类,哪怕子类实例调也不变?
因为 :: 左边的类名(或 self/parent)在编译期就决定了绑定目标,和运行时对象类型、$this 是谁完全无关。这不是 bug,是设计——静态调用不走虚函数表。
立即学习“PHP免费学习笔记(深入)”;
-
ParentClass::foo()→ 永远执行ParentClass里定义的foo -
$obj::foo()等价于get_class($obj)::foo(),但若该类没重写,会继续向上查父类,不是查$obj的实际类型 - 想实现“子类调用自动走子类逻辑”,必须用
static::foo(),且确保子类真有这个方法
最常被忽略的是:静态调用的“类上下文”由语法位置决定,而不是执行栈或对象实例。看代码时盯紧 :: 左边写的是什么,比调试运行时更管用。











