7

在 PHP 8.1 中,以下代码在以前的版本中有效:

class Example implements Countable {
    public function count() {
        return 42;
    }
}

发出弃用通知:

不推荐使用:Example::count() 的返回类型应该与 Countable::count(): int 兼容,或者应该使用 #[\ReturnTypeWillChange] 属性来暂时抑制通知

这是什么意思,我应该如何解决?

4

1 回答 1

7

背景:返回类型和协方差

自 PHP 7.0 起,可以指定函数或方法的返回类型,例如function example(): string指示返回字符串的函数。这形成了其他代码可以依赖的合约。

例如,此类承诺该getList方法将返回某种Iterator

class Base {
    public function getList(): Iterator {
       // ...
    }
}

可以编写调用代码,知道如果$foo instanceOf Base为真,那么$foo->getList() instanceOf Iterator也为真。

如果扩展类,可以指定相同的返回类型,或更具体的返回类型(称为“协方差”的规则),调用代码的假设仍然成立:

class SubClass extends Base {
    public function getList(): DirectoryIterator {
        // ...
    }
}
$foo = new SubClass;
var_dump($foo instanceOf Base); // true
var_dump($foo->getList() instanceOf Iterator); // true

但是如果你指定一个不同的返回类型,或者根本没有返回类型,假设就会失效,所以 PHP 不允许你这样做:

class NotPossible extends Base {
    public function getList(): bool {
        return false;
    }
}
// Fatal error: Declaration of NotPossible::getList(): bool must be compatible with Base::getList(): Iterator
// If the error didn't happen...
$foo = new NotPossible;
var_dump($foo instanceOf Base); // would be true
var_dump($foo->getList() instanceOf Iterator); // would be false!

向后兼容性和弃用

如果将返回类型添加到现有类或接口,则扩展或实现的每个类也必须更改,否则将给出与上NotPossible例相同的错误。

在 PHP 8.0中加入了Union Types,可以指定大部分内部函数和方法的返回类型;但是为任何未标记的类或接口方法指定它final会立即破坏大量代码。

因此,相反,添加了“暂定”返回类型的概念:记录了正确的返回类型,但通常会出现错误的是问题中显示的弃用通知。

#[\ReturnTypeWillChange]属性_

额外的问题是很多代码需要能够在多个 PHP 版本上运行,并且一些添加的返回类型在 8.0 之前的版本中无效。因此,要在代码中指示对返回类型的计划更改,您可以添加特殊属性 #[\ReturnTypeWillChange]。这看起来像是对旧版本 PHP 的注释,但告诉 PHP 8.1 不要提出弃用通知。然后,一旦您不需要支持旧版本的 PHP,您就可以修复返回类型。

你现在应该怎么做?

首先,仔细阅读消息,找出需要更改的方法,以及正确的返回类型是什么。在上面的例子中:

Example::count() 的返回类型 ...

这说类的count方法Example需要改变......

... 应该与 Countable::count(): int 兼容

...并且预期的返回类型是int,如Countable接口上定义的那样

接下来,决定你能做什么:

  • 您的课程是否已经返回正确的类型?在我们的示例中,是的,42对于返回类型为int.
  • 你能安全地改变方法的返回类型吗?如果您正在开发自己的应用程序,答案可能是“是”,只要您更新该类extend。如果您正在处理用户可能扩展了此类的库代码,则需要考虑对他们的影响。

如果您认为它是安全的,您可以简单地添加返回类型,如通知中所示:

class Example implements Countable {
    public function count(): int {
        return 42;
    }
}

如果您需要支持旧版本的 PHP,或者尚未更新代码的用户,您可以暂时取消通知:

class Example implements Countable {
    #[\ReturnTypeWillChange]
    public function count() {
        return 42;
    }
}

重要的是要注意内部返回类型可能会在 PHP 9.0 中强制执行,因此请确保您有一个可靠的计划来更改使用此属性标记的方法。

于 2022-02-15T21:41:51.193 回答