__CLASS__返回定义时的类名而非运行时类名,如Dog调用继承自Animal的getName()仍输出"Animal";应使用get_class($this)或static::class获取真实类名。

PHP中__CLASS__返回的是定义时的类名,不是运行时的实际类名
这是最容易误解的一点:__CLASS__在类定义内部写死,编译期就确定了,哪怕在子类里继承并直接使用它,拿到的仍是父类名。比如:
class Animal { public function getName() { return __CLASS__; } }
class Dog extends Animal {}
echo (new Dog)->getName(); // 输出 "Animal",不是 "Dog"
如果你要获取当前实例的真实类名,得用get_class($this)或static::class(PHP 5.5+)。
-
get_class($this):安全、兼容老版本,但需确保$this存在(不能在静态方法里直接用) -
static::class:更简洁,支持后期静态绑定(LSB),推荐用于静态上下文或需要真实运行时类名的场景 -
self::class:和__CLASS__行为一致,也是定义处的类名,不随调用者变化
在静态方法里用__CLASS__会出什么问题?
不会报错,但结果往往不符合预期——它仍返回声明该静态方法的类名,而非调用它的子类名。例如:
class A { public static function who() { return __CLASS__; } }
class B extends A {}
echo B::who(); // 还是输出 "A"
这时候必须换用static::class:
class A { public static function who() { return static::class; } }
echo B::who(); // 输出 "B"
- 若兼容 PHP get_called_class()(仅限静态上下文)
- 注意
get_called_class()在非静态调用或未通过类名调用时返回false,需判空 -
__CLASS__在trait中使用时,返回的是trait被引入的那个类的名称(即宿主类名),不是trait自身名
__CLASS__ vs get_class() vs static::class 性能与适用场景
三者开销差异极小,但语义和可靠性不同:
-
__CLASS__:编译期常量,最快,但“静态”;适合写配置、日志前缀等不依赖实际调用链的场景 -
get_class($obj):运行时反射,稍慢一点,但最稳妥;可用于任意对象,包括null以外的任何实例 -
static::class:语法糖,底层仍走LSB机制,性能接近__CLASS__;唯一要求是必须在类作用域内,且有有效的静态调用上下文
别在函数参数默认值、const定义、数组键这类编译期求值位置用static::class——会报Parse error: syntax error,因为此时还没进入运行时绑定阶段。
trait里想获取“真正使用它的类名”,不能只靠__CLASS__
trait本身没有类名,__CLASS__在trait内部展开时,指向的是最终引入它的那个类(即宿主类)。但如果你在trait里需要区分是被App\Model\User还是App\Model\Post引入,就得结合上下文判断:
- 用
static::class代替__CLASS__,它会在trait方法被调用时解析为实际调用类 - 若方法是静态的,
static::class依然有效;若方法是非静态的,$this存在,也可用get_class($this) - 避免在trait的
__construct或属性初始化中硬编码__CLASS__,那会锁死到第一个引入它的类
真正麻烦的是跨命名空间继承+trait混用时,static::class返回带完整命名空间的字符串,而__CLASS__也带命名空间——但两者可能指向不同层级,这点容易在日志或路由映射中埋下隐性bug。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











