在这种简单的情况下 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 对象系统的不幸现状。