self指向定义方法的类,static指向实际调用类(后期静态绑定);使用static可使子类覆盖静态属性和方法,实现多态,而self会锁死父类上下文。

PHP中self和static在继承里行为不同
调用父类方法时,self永远指向定义该方法的类,而static指向实际调用时的类(即“后期静态绑定”)。这不是语法糖差异,是运行时解析逻辑的根本区别。
- 常见错误现象:
self::foo()在子类里调用父类方法,结果却调用了父类自己的foo(),而非子类重写的版本 - 使用场景:写可被继承的基类工具方法(比如工厂、单例、配置加载),需要让子类能自然覆盖行为
- 参数差异:两者都不接受参数,但绑定目标不同直接影响
static属性、private方法可见性、以及final限制是否生效
什么时候必须用static代替self
当你希望子类能“接管”静态调用链,尤其是涉及静态属性或需复用父类逻辑但替换具体实现时。self在这里会锁死上下文,导致子类无法参与多态。
- 典型例子:基类
BaseModel有个create()方法,内部用self::$table——子类User改写了$table,但self::$table仍读父类值;换成static::$table才对 - 性能影响:无。延迟绑定是PHP 5.3+的语法层特性,不增加运行时开销
- 兼容性注意:PHP static后期绑定,会报
Parse error: syntax error
self没毛病,但别误以为它“更安全”
很多人觉得self明确、可控,所以默认用它。其实它只是“确定”,不是“正确”。如果类设计本身预期被继承,self反而制造隐性bug。
- 容易踩的坑:在抽象基类里用
self::getInstance()实现单例,子类调用时返回的仍是基类实例,而非子类自身实例 - 反例代码:
abstract class A { protected static $instance; public static function getInstance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } }这里new self()在B extends A中执行,实际是new A(),不是new B() - 修复方式:把
self全换成static,并确保构造函数不是private(否则static也无法实例化子类)
静态属性和static绑定的关系最易混淆
静态属性本身不自动随static关键字“继承”或“覆盖”,而是靠类作用域隔离。static::$prop读的是当前类作用域下的同名静态属性,哪怕它没显式声明。
- 若子类未声明
static $prop,static::$prop会回退到父类的$prop(如果可见);但一旦子类定义了,就完全独立 - 对比:
self::$prop永远只读父类定义的那个,哪怕子类有同名属性也视而不见 - 调试技巧:用
get_called_class()确认当前static指向哪个类,比猜更可靠
事情说清了就结束。真正难的不是记住self和static的区别,而是写基类时提前想清楚:这个方法/属性,到底该由定义者控制,还是由使用者控制。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











