static:: 解决 self:: 无法处理的继承场景,实现后期静态绑定:运行时确定调用类,支持子类隔离静态属性与方法;必须用于工厂方法、单例基类等需多态行为的静态场景。
self:: 在定义时就绑定到当前类,不管子类怎么继承,它始终调用定义它的那个类的成员;static:: 则是运行时才确定绑定目标,支持“后期静态绑定”(Late Static Binding),也就是真正指向 new 出来的那个类。这不是优劣问题,而是用途不同:你需要多态行为时,static:: 是唯一选择。
self::method(),子类调用时仍执行父类的 method
static::method(),子类调用
时会优先找自己是否重写了该方法,没重写才向上查找$this,但 static:: 可以配合 get_called_class() 获取实际调用类名典型场景是工厂方法、单例基类、静态属性初始化等需要子类隔离行为的地方。比如一个抽象基类想让每个子类维护自己的静态缓存数组,用 self::$cache 会导致所有子类共享同一份数组;而 static::$cache 每个子类实例化后都拥有独立副本。
static $instances = []; 的单例基类,子类需各自管理实例 → 必须用 static::$instances
public static function create(),希望返回调用者类的新实例 → 必须用 new static()
static::class 获取当前调用类完整命名空间(比 __CLASS__ 更准确)static:: 只能在静态上下文中使用,且它不持有运行时对象状态。常见误用是试图在非静态方法里用 static:: 去调用需要 $this 的实例方法,这会报 Cannot access static:: when no class scope is active 或直接逻辑错误。
static::someMethod() 是合法的,但 someMethod 必须是 static 的static:: 无法访问 $this->property,哪怕该 property 是 public 的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::,而是判断某个静态行为是否本该属于类层级 —— 很多时候,把它变成实例方法 + 依赖注入,反而更清晰、更易测、更少绑定。