在这个简单的情况下,PHP 拒绝接受返回类型背后的原因是什么?



在 PHP 7.1.4 中,使用严格的类型,我有一个简单的面向对象的设置,涉及一些接口,以及一些实现这些接口的类。如您所料,下面的示例工作正常。

declare(strict_types=1);
interface Loginable {
public function login();
}
interface Upgradeable {
public function upgrade(): Loginable;
}
class Person implements Upgradeable {
function upgrade(): Loginable {
return new PersonAccount();
}
}
class PersonAccount implements Loginable {
public function login() {
;
}
}

请注意,可升级界面中的升级函数需要可登录返回类型,这是另一个接口。在此示例中,Person 类内的升级方法将可登录接口指定为其返回类型,以匹配接口的规定。

但是,如果我现在尝试更准确地指定 Person 类的升级方法的返回类型,则会遇到致命错误。

class Person implements Upgradeable {
function upgrade(): PersonAccount {
return new PersonAccount();
}
}

请注意,我在这里要完成的是指定升级方法将根据类实现的接口返回一个实现接口的对象,该接口是必需的返回类型。这对我来说似乎是非常合乎逻辑和正确的,但是,PHP 会说:

致命错误:声明人员::升级():

人员帐户必须与可升级::升级():可在 [...] 中登录

正如 yivi 在 https://stackoverflow.com/a/49353076/9524284 上已经指出的那样,我试图完成的事情是不可能的。

如果涉及扩展类,我会接受 PHP 的抱怨,因为扩展类可以覆盖原始方法,这样就无法保证正确的返回类型。但是,在上述方案中,不会扩展类。只有接口的实现,其全部目的是显式保证正确的实现。

请阐明 PHP 拒绝接受上述声明返回类型的方式背后的原因!

您正在描述一种称为协方差的类型推理特征,它本身就是Liskov替换原理的结果。


从 PHP 7.4 开始,这符合您的预期。(有关详细信息,请参阅实现该行为的 RFC。


在此之前,这是在内部讨论的。正如在一次这样的对话中所说:

如果实现优于满足接口定义的要求,则它应该能够实现该接口。

所以,是的,PHP应该允许你描述的协方差。但要意识到:不是PHP拒绝实现协方差,而是PHP还没有实现协方差。这样做有一些技术障碍,但它们并非不可逾越。正如核心维护者在内部的同一线程中所述:

这是可行的,只是没有完成。

如果您想生成 RFC 和 PR,请这样做。在那之前,这只是不断发展的PHP对象系统的不幸现状。

最新更新