new self() 创建定义该方法的类的实例,编译期确定;new static() 创建实际调用类的实例,运行时确定,支持后期静态绑定。

new self() 和 new static() 创建的实例类型完全不同
这是最容易引发隐蔽 bug 的地方,尤其在工厂方法、单例或 Builder 模式中。调用链上看似一样的方法,返回的却可能是父类实例而非预期的子类实例。
-
new self()总是创建定义该方法的那个类的实例,编译期就锁死类名 -
new static()创建的是「当前对象所属类」或「实际调用该静态方法的类」的实例,运行时才确定 - 如果父类里写
public static function make() { return new static(); },子类Child::make()返回Child实例;换成new self()就永远返回父类实例 - PHP 5.3+ 才真正支持
static的后期绑定;低版本中static::会退化为self::行为,不报错但逻辑错误
访问静态属性时 self::$prop 和 static::$prop 可能读到不同值
当子类重写了父类的同名静态属性,self 和 static 指向的内存位置根本不同 —— 它们不是“值不同”,而是“根本不在同一处”。
-
self::$name始终读取定义该方法的类的静态属性(比如Base::$name),哪怕在Derived中调用 -
static::$name会顺着调用栈找到最末端那个类的同名属性(比如Derived::$name) - 这种差异在配置类、状态管理器、多租户上下文等场景中极易导致逻辑错乱:你以为改了子类配置,结果父类方法还在读老值
static::method() 支持静态多态,self::method() 不支持
静态方法本身不能被覆盖(overridden),但通过 static:: 可以实现类似效果:让父类中定义的方法,在子类调用时自动路由到子类中同名的静态方法。
-
self::who()在父类方法里写死调用父类who(),子类即使定义了自己的who()也不会触发 -
static::who()在子类调用时,会查找子类是否定义了who();有则调用,没有才向上找 —— 这就是“后期静态绑定”的实质 - 这个机制只对静态方法和静态属性生效;
$this->method()是动态绑定,不在此列 - 注意:若子类没定义该方法,
static::会继续向上查找,不是直接报错
什么时候必须用 static 而不能用 self
不是“推荐用”,而是“不用就错”。以下场景一旦误用 self,代码行为就会与设计意图背道而驰:
- 构建器模式中返回
new static()以保持链式调用返回当前子类实例 - 单例的
getInstance()方法需返回当前类的唯一实例,而非父类实例 - 抽象基类提供通用静态工厂方法,期望子类继承后能自动适配自身类型
- 日志、监控等横切关注点中,需要获取调用方类名(
get_called_class()返回值与static::一致)
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











