PHP 8.3 新特性 - Override 属性

作者: 温新

图书: 【PHP 8.3 新特性】

阅读: 654

时间: 2024-11-21 04:35:42

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 类是一个重复声明,这将导致错误。

请登录后再评论