Background: Return types and covariance
自PHP7.0以来,可以指定函数或方法的return type,例如function example(): string
,以指示返回字符串的函数.这形成了一个其他代码可以依赖的contract.
例如,这个类promise getList
方法将返回某种Iterator
:
class Base {
public function getList(): Iterator {
// ...
}
}
编写调用代码时可以知道,如果$foo instanceOf Base
为真,那么$foo->getList() instanceOf Iterator
也将为真.
如果扩展该类,可以指定same返回类型或a more specific返回类型(称为"协方差"的规则),调用代码的假设仍然为真:
class SubClass extends Base {
public function getList(): DirectoryIterator {
// ...
}
}
$foo = new SubClass;
var_dump($foo instanceOf Base); // true
var_dump($foo->getList() instanceOf Iterator); // true
但是,如果指定different返回类型,或者no return type at all,那么假设就不成立了,所以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!
Backwards compatibility and deprecation
如果向现有类或接口添加一个返回类型,则扩展或实现must的每个类也会发生更改,否则它将给出与上述NotPossible
示例相同的错误.
PHP8.0中增加了Union Types,可以指定大多数内部函数和方法的返回类型;但为任何未标记为final
的类或接口方法指定它会立即 destruct 大量代码.
因此,取而代之的是,增加了"暂定"退货类型的概念:正确的退货类型已记录在案,但通常会出现错误的是问题中显示的弃用通知.
The #[\ReturnTypeWillChange]
attribute
另外一个问题是,许多代码需要能够在多个版本的PHP上运行,而且添加的一些返回类型在8.0之前的版本中无效.因此,为了在代码中指示对返回类型的planned更改,可以添加特殊的attribute #[\ReturnTypeWillChange]
.这看起来像是对旧版本PHP的 comments ,但告诉PHP8.1不要提出反对通知.然后,一旦不需要支持旧版本的PHP,就可以修复返回类型.
What should you do now?
首先,仔细阅读信息,找出需要更改的方法,以及正确的返回类型.在上面的例子中:
返回示例的类型::count()...
这说明Example
类的count
方法需要改变...
... 应该与Countable::count()兼容:int...
... 预期的返回类型是int
,如Countable
接口上定义的
接下来,决定你能做什么:
- 你的类是否已经返回了正确的类型?在我们的示例中,是的,
42
对于int
的返回类型有效.
- 您能安全地更改方法的返回类型吗?如果你正在开发自己的应用程序,答案可能是"是的",只要你更新了
extend
个这样的类.如果您正在处理用户可能已经扩展了该类的库代码,则需要考虑对它们的影响.
如果你认为它是安全的,你可以简单地按照通知中所示的add the return type:
class Example implements Countable {
public function count(): int {
return 42;
}
}
如果您需要支持旧版本的PHP,或者尚未更新代码的用户,您可以取消以下通知:
class Example implements Countable {
#[\ReturnTypeWillChange]
public function count() {
return 42;
}
}
需要注意的是,内部返回类型可能是enforced in PHP 9.0,因此请确保您有一个可靠的计划来更改使用此属性标记的方法.