在这种简单的情况下 PHP 拒绝接受 return 类型背后的原因是什么?
What is the reasoning behind the refusal of PHP to accept the return types in this simple situation?
在 PHP 7.1.4 中,使用严格类型,我有一个简单的面向对象的设置,涉及一些接口,一些 classes 实现这些接口。如您所料,下面的示例工作正常。
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() {
;
}
}
请注意 Upgradable 接口中的升级功能如何需要 Loginable return 类型,这是另一个接口。 Personclass中的upgrade方法,在这个例子中,指定一个Loginable接口作为它的return类型来匹配接口的规定。
但是,如果我现在尝试更准确地指定 return 类型的 Person class 升级方法,我 运行 会陷入致命错误。
class Person implements Upgradeable {
function upgrade(): PersonAccount {
return new PersonAccount();
}
}
请注意,我在这里试图完成的是指定升级方法将 return 实现接口的对象,该接口是根据实现的接口 return 类型class。这对我来说似乎非常合乎逻辑且正确,但是,PHP 会说:
Fatal Error: Declaration of Person::upgrade(): PersonAccount must be compatible with Upgradeable::upgrade(): Loginable in [...]
正如 yivi at 已经指出的那样,我想要实现的目标是不可能的。
PHP的投诉如果有扩展的class我会接受,因为扩展的class可以覆盖原来的方法,这样就没有保障了正确的 return 类型。但是,在上述场景中,classes 没有被扩展。只有接口的实现,其全部目的是明确保证正确实现。
请阐明 PHP 拒绝接受上述 return 类型声明方式的原因!
您描述的是一种称为协方差的 type-reasoning 特征,它本身就是 Liskov 替换原则的结果。
从 PHP 7.4 开始,this works as you expect. (See the RFC 实施行为以获取详细信息。)
在此之前,这是在内部讨论的。正如 one such conversation 中所述:
if an implementation better than satisfies the requirements defined by an interface, it should be able to implement that interface.
所以,是的,PHP 应该 允许如您所描述的协方差。但请注意:并不是 PHP 拒绝实现协变,而是 PHP has not yet implemented covariance。这样做有一些技术障碍,但并非不可逾越。正如核心维护者在内部的同一线程中所述:
It's doable, it just hasn't been done.
如果您想生成 RFC 和 PR,请这样做。在那之前,这只是 ever-evolving PHP 对象系统的不幸现状。
在 PHP 7.1.4 中,使用严格类型,我有一个简单的面向对象的设置,涉及一些接口,一些 classes 实现这些接口。如您所料,下面的示例工作正常。
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() {
;
}
}
请注意 Upgradable 接口中的升级功能如何需要 Loginable return 类型,这是另一个接口。 Personclass中的upgrade方法,在这个例子中,指定一个Loginable接口作为它的return类型来匹配接口的规定。
但是,如果我现在尝试更准确地指定 return 类型的 Person class 升级方法,我 运行 会陷入致命错误。
class Person implements Upgradeable {
function upgrade(): PersonAccount {
return new PersonAccount();
}
}
请注意,我在这里试图完成的是指定升级方法将 return 实现接口的对象,该接口是根据实现的接口 return 类型class。这对我来说似乎非常合乎逻辑且正确,但是,PHP 会说:
Fatal Error: Declaration of Person::upgrade(): PersonAccount must be compatible with Upgradeable::upgrade(): Loginable in [...]
正如 yivi at
PHP的投诉如果有扩展的class我会接受,因为扩展的class可以覆盖原来的方法,这样就没有保障了正确的 return 类型。但是,在上述场景中,classes 没有被扩展。只有接口的实现,其全部目的是明确保证正确实现。
请阐明 PHP 拒绝接受上述 return 类型声明方式的原因!
您描述的是一种称为协方差的 type-reasoning 特征,它本身就是 Liskov 替换原则的结果。
从 PHP 7.4 开始,this works as you expect. (See the RFC 实施行为以获取详细信息。)
在此之前,这是在内部讨论的。正如 one such conversation 中所述:
if an implementation better than satisfies the requirements defined by an interface, it should be able to implement that interface.
所以,是的,PHP 应该 允许如您所描述的协方差。但请注意:并不是 PHP 拒绝实现协变,而是 PHP has not yet implemented covariance。这样做有一些技术障碍,但并非不可逾越。正如核心维护者在内部的同一线程中所述:
It's doable, it just hasn't been done.
如果您想生成 RFC 和 PR,请这样做。在那之前,这只是 ever-evolving PHP 对象系统的不幸现状。