php中static::和self::哪个好_后期静态绑定的选择技巧【教程】

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::,而是判断某个静态行为是否本该属于类层级 —— 很多时候,把它变成实例方法 + 依赖注入,反而更清晰、更易测、更少绑定。