self::在编译时绑定定义类,不支持静态多态;static::在运行时绑定调用类,实现后期静态绑定;静态属性不继承,需子类显式声明才能独立存储。

self:: 总是硬编码到定义它的那个类
你在 Base 类里写 self::method(),哪怕子类 Child 继承并调用了这个方法,最终执行的仍是 Base::method()。PHP 在编译阶段就锁死了这个绑定,不看调用链,只看代码写在哪。这导致子类覆盖的同名静态方法完全不会被触发。
常见错误现象:self::$config 在父类中初始化为 ['env' => 'prod'],子类重写了 static $config = ['env' => 'dev'],但父类方法里用 self::$config 读出来的还是 prod —— 因为它根本没去子类查。
-
self不支持静态多态,适合写死行为(比如工具类内部固定逻辑) - 在 PHP 5.2 及更早版本中,
static不可用,self是唯一选择 - 若你明确不想让子类影响行为(例如日志前缀、固定错误码),
self反而是安全的
static:: 触发后期静态绑定(Late Static Binding)
static:: 不是“当前类”,而是“谁调的,就找谁”。它在运行时才确定目标类,所以能正确路由到子类中重写的静态属性或方法。这是 PHP 5.3+ 引入的核心机制,不是语法糖,是底层解析逻辑的改变。
使用场景:工厂方法、单例基类、可继承的配置类。例如一个 create() 方法返回实例,用 new static() 才能确保返回的是 Child 实例,而不是硬编码的 Base 实例。
- 必须在静态上下文(
public static function)中使用,$this里不能用static:: - 若调用链是
GrandChild::foo()→Parent::foo(),其中Parent::foo()写了static::bar(),则实际调用的是GrandChild::bar() - 低于 PHP 5.3 的环境会报
Parse error: syntax error或静默退化为self行为(不可靠)
new self() 和 new static() 实例化结果完全不同
这是最容易出 bug 的地方,尤其在抽象基类或构建器模式中。前者永远创建定义该语句的类的实例;后者创建的是**当前调用栈最末端那个类**的实例。
示例:Base 类有 public static function make() { return new self(); },Child extends Base 调用 Child::make(),返回的是 Base 对象;换成 new static(),返回才是 Child 对象。
- 单例模式中若用
new self(),子类调用会拿到父类实例,破坏单例契约 - 类型提示(如
function expects Base)可能因返回类型不符而报错 - 构造函数参数、
__construct()中的逻辑都按实际类执行,不是按定义类
静态属性继承的陷阱:它们根本不继承
PHP 中静态属性不随继承复制,所有子类共享父类的同一份存储。也就是说:Base::$data 被 Child1::$data = 'a' 和 Child2::$data = 'b' 先后赋值,最后读出来是 'b' —— 因为它们操作的都是 Base::$data。
这和 self/static 无关,是语言设计本身的问题。想实现“每个子类独立一份”,必须显式声明:
- 子类中重新声明
public static $data(哪怕只是= null) - 用
static::$data访问,确保写入的是子类自己的副本 -
self::$data仍会写入父类,无法解耦
复杂点在于:这个机制和后期静态绑定是正交的。即使你用了 static::,如果子类没显式声明静态属性,它依然会落到父类上。别指望 static 自动帮你隔离存储。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











