gpt4 book ai didi

PHP 接口(interface)和参数继承

转载 作者:行者123 更新时间:2023-12-04 18:03:08 24 4
gpt4 key购买 nike

我的项目中有实体和存储库。为了简化,我有

  • 实体接口(interface)
  • 用户实体
  • 商业实体

接口(interface):

interface Entity
{
/**
* @return EntityId
*/
public function getId();
}

实现

class UserEntity implements Entity
{
/**
* @return EntityId
*/
public function getId(){
//...do something here for return
return $userId;
}
}

class BusinessEntity implements Entity
{
/**
* @return EntityId
*/
public function getId(){
//...do something here for return
return $userId;
}
}

我想定义一个 Repository 基本功能,比如 save,所以我的界面看起来像这样:

interface Repository
{
/**
* @param Entity $entity
*
* @throws \InvalidArgumentException If argument is not match for the repository.
* @throws UnableToSaveException If repository can't save the Entity.
*
* @return Entity The saved entity
*/
public function save(Entity $entity);
}

后来,我对不同类型的存储库有不同的接口(interface),比如 UserRepositoryBusinessRepository

interface BusinessRepository extends Repository
{
/**
* @param BusinessEntity $entity
*
* @throws \InvalidArgumentException If argument is not match for the repository.
* @throws UnableToSaveException If repository can't save the Entity.
*
* @return Entity The saved entity
*/
public function save(BusinessEntity $entity);
}

上面的代码失败了,因为Declaration must be compatible with Repository...

但是 BusinessEntity 实现了 Entity,因此它是兼容的。

我有很多类型的实体,所以如果我不能进行类型提示,我总是需要检查传递的实例是否是我需要的 instanceof。这很愚蠢。

以下代码再次失败:

class BusinessRepository implements Repository
{
public function save(BusinessEntity $entity)
{
//this will fail, however BusinessEntity is an Entity
}
}

最佳答案

一般来说,方法参数必须相对于继承层次结构或不变量是逆变的。这意味着当用作方法参数的类型时,BusinessEntity 确实与实体“兼容”。

从“契约(Contract)”的角度来考虑。您的接口(interface) Repository promises 它的方法 save 可以处理 Entity 类型的参数。从 Repository 继承的子类型应该绑定(bind)到这个引入的契约(否则,如果您不能确定类型 promise 能够做什么,那么首先定义类型有什么意义?) .

现在,如果一个子类型突然只接受更特殊的类型,比如 BusinessEntity,但不再接受 Entity,契约就被打破了。您不能再将 BusinessRepository 用作 Repository,因为您不能使用 Entity 调用 save

起初这是违反直觉的,但看看这个:https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Contravariant_method_argument_type

注意图中的继承箭头。

要做什么?摆脱继承是面向对象编程中的 chalice 的想法。大多数时候,它不是,并引入了各种讨厌的耦合。例如,支持组合而不是继承。看看Parameter type covariance in specializations .

关于PHP 接口(interface)和参数继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31657261/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com