PHP 8.3 新特性 - Override 属性
PHP 8.3 新特性 - Override 属性
hi,我是温新,一名 PHPer
在 PHP 8.3 中,引入了一个新的 #[\Override] 属性,用于注解方法,用于标记一个方法覆盖了父类或接口中的方法。
#[\Override] 可以用在接口、类、Trait、枚举中。
当在子类中定义一个与父类同名的方法时,可以使用 #[\Override] 属性来明确表示该方法是对父类方法的覆盖。这样可以提高代码的可读性,并帮助开发者更好地理解方法的继承关系。
类继承
先来看看 PHP 8.3 之前,子类重写父类的案例。
<?php
class Human {
    public function say()
    {
        echo '人类';
    }
}
class Person extends Human {
    // 重写父类方法
    public function say()
    {
        echo '王美丽';
    }
}
$mei = new Person;
$mei->say();
再来看看 PHP 8.3 及更高版本的写法
class Person extends Human {
<?php
class Human {
    public function say()
    {
        echo '人类';
    }
}
class Person extends Human {
    // 使用该注解表名这个方法是重写父类的方法
    #[\Override]
    public function say()
    {
        echo '王美丽';
    }
}
$mei = new Person;
$mei->say();
子类中有 #[\Override],而父类中没有,子会报错
PHP Fatal error:  Person::say() has #[\Override] attribute, but no matching parent method exists in
也就是说,只要子类有 #[\Override],那么父类必需有子类所重写的方法。
#[\Override] 属性类概要
#[Attribute(Attribute::TARGET_METHOD)]
final class Override {
    public function __construct() {}
}
- 
\Override属性在全局命名空间中声明。 
带有 #[\Override] 属性的类方法必须有一个父方法或接口方法。这个属性在任何具有该属性的 trait/enum/interface/class 方法中都保持一致可用。
接口
<?php
interface Animal {
    public function say();
}
interface Dog extends Animal {
    #[\Override]
    public function say();
}
class Cat implements Dog {
    #[\Override]
    public function say()
    {
        echo '喵喵';
    }
}
$cat = new Cat;
$cat->say()
这个案例演示了接口的继承的同时,还演示了类实现接口,其中都使用到了 #[\Override] 注解,表明是继承或重写父类方法。
枚举
Enum 不能扩展另一个Enum,但 Enum 仍然可以实现接口,并且 #[\Override] 属性也可以应用于 Enum 方法。
<?php
interface AnimalInterface {
    public function say(): void;
}
enum AnimalEnum implements AnimalInterface {
    case COLOR;
    case AGE;
    #[\Override]
    public function say(): void {
        echo 'hello 来自 AnimalEnum';
    }
}
class Cat implements AnimalInterface {
    #[\Override]
    public function say(): void {
        echo 'hello 来自 Cat';
    }
}
function callSay(AnimalInterface $instance): void {
    $instance->say();
}
callSay(AnimalEnum::COLOR); // hello 来自 AnimalEnum
$cat = new Cat;
callSay($cat); // hello 来自 Cat
Traits
在 traits 中,#[\Override]方法非常有用。在引入#[\Override]属性之前,声明 trait 方法并确保使用该 trait 的类将覆盖该方法的唯一方法是将该方法声明为抽象的。
有了#[\Override]属性,现在可以强制使用它的类覆盖 trait 方法。
<?php
trait MyTrait {
    #[\Override]
    public function myMethod() {
        echo 'MyTrait';
    }
}
class MyClass {
    use MyTrait;
    public function myMethod(): void {
        echo "MyClass!";
    }
}
function callMyMethod(MyClass $instance): void {
    $instance->myMethod();
}
// 创建 MyClass 的实例并调用 myMethod()
$myClass = new MyClass();
callMyMethod($myClass); // 输出: MyClass!
我们来看看下面这种情况,它会报错
<?php
trait MyTrait {
    #[\Override]
    public function myMethod() {
        echo 'MyTrait';
    }
}
class MyClass {
    use MyTrait;   
}
PHP Fatal error:  MyClass::myMethod() has #[\Override] attribute, but no matching parent method exists in 
在这个案例中,如果 MyClass 没有重写 MyTrait 中的 myMethod() 方法就会报错。从这里可以知道,如果某个 trait 中含有 #[\Override]标注的方法,那么使用的类中就必需重写被标注的方法。
#[\Override] 是 PHP 8.3 新增的属性。设计上,类的存在不会在编译时进行验证。在先前的 PHP 版本中,向类方法添加 #[\Override] 属性不会有任何效果,但也不会引发任何语法或其他错误。
注意
由于 # 字符在 PHP 中被解释为代码注释,因此在任何 PHP 7 或旧应用程序中添加任何属性都不会引发任何语法错误。
#[\Override] 属性类可以在用户端的 PHP 代码中进行填充。它不会带来功能,但任何检查类方法属性的代码都将能够实例化一个 \Override 实例。
如果任何 PHP 应用程序在全局命名空间中声明自己的 \Override 类,由于用户端的 \Override 类是一个重复声明,这将导致错误。