static:: 解决 self:: 无法处理的继承场景,实现后期静态绑定:运行时确定调用类,支持子类隔离静态属性与方法;必须用于工厂方法、单例基类等需多态行为的静态场景。

static:: 不是“更好”,而是解决 self:: 无法处理的继承场景
self:: 在定义时就绑定到当前类,不管子类怎么继承,它始终调用定义它的那个类的成员;static:: 则是运行时才确定绑定目标,支持“后期静态绑定”(Late Static Binding),也就是真正指向 new 出来的那个类。这不是优劣问题,而是用途不同:你需要多态行为时,static:: 是唯一选择。
- 如果在父类里写
self::method(),子类调用时仍执行父类的method - 如果写
static::method(),子类调用时会优先找自己是否重写了该方法,没重写才向上查找 - 两者都不能访问非静态上下文中的
$this,但static::可以配合get_called_class()获取实际调用类名
什么时候必须用 static:: 而不能用 self::
典型场景是工厂方法、单例基类、静态属性初始化等需要子类隔离行为的地方。比如一个抽象基类想让每个子类维护自己的静态缓存数组,用 self::$cache 会导致所有子类共享同一份数组;而 static::$cache 每个子类实例化后都拥有独立副本。
- 定义了
static $instances = [];的单例基类,子类需各自管理实例 → 必须用static::$instances - 父类有
public static function create(),希望返回调用者类的新实例 → 必须用new static() - 使用
static::class获取当前调用类完整命名空间(比__CLASS__更准确)
容易踩的坑:static:: 不等于 $this,也不能替代对象方法调用
static:: 只能在静态上下文中使用,且它不持有运行时对象状态。常见误用是试图在非静态方法里用 static:: 去调用需要 $this 的实例方法,这会报 Cannot access static:: when no class scope is active 或直接逻辑错误。
- 在普通方法中写
static::someMethod()是合法的,但someMethod必须是static的 -
static::无法访问$this->property,哪怕该 property 是 public 的 - PHP 5.3+ 才支持
static::,低于此版本会解析失败 - 过度依赖
static::可能掩盖设计问题:频繁需要后期绑定,往往说明该逻辑更适合用对象组合或策略模式
abstract class Repository {
protected static $cache = [];
public static function setCache($key, $value) {
// ❌ self::$cache 共享给所有子类
// ✅ static::$cache 让 UserRepo、PostRepo 各自独立
static::$cache[$key] = $value;
}
public static function getInstance() {
$class = static::class;
return new $class();
}
}
class UserRepo extends Repository {}
class PostRepo extends Repository {}
UserRepo::setCache('users', ['a', 'b']);
PostRepo::setCache('posts', [1, 2]);
// UserRepo::$cache === ['users' => [...]]
// PostRepo::$cache === ['posts' => [...]]
真正难的不是选 static:: 还是 self::,而是判断某个静态行为是否本该属于类层级 —— 很多时候,把它变成实例方法 + 依赖注入,反而更清晰、更易测、更少绑定。











