扩展抽象类时,是否可以将类型提示重新定义为后代类? [英] Is there a way to redefine a type hint to a descendant class when extending an abstract class?

查看:69
本文介绍了扩展抽象类时,是否可以将类型提示重新定义为后代类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将使用以下示例来说明我的问题:

I will be using the following example to illustrate my question:

class Attribute {}

class SimpleAttribute extends Attribute {}



abstract class AbstractFactory {
    abstract public function update(Attribute $attr, $data);
}

class SimpleFactory extends AbstractFactory {
   public function update(SimpleAttribute $attr, $data);

}

如果尝试运行此命令,PHP将抛出一个致命错误,提示Declaration of SimpleFactory::update() must be compatible with that of AbstractFactory::update()

If you try to run this, PHP will throw a fatal error, saying that the Declaration of SimpleFactory::update() must be compatible with that of AbstractFactory::update()

我完全理解这是什么意思:SimpleFactory::update()的方法签名必须与其父抽象类的签名完全匹配.

I understand exactly what this means: That SimpleFactory::update()s method signature must exactly match that of its parent abstract class.

但是,我的问题是:有什么方法可以允许具体方法(在本例中为SimpleFactory::update())将类型提示重新定义为原始提示的有效后代吗?

However, my question: Is there any way to allow the concrete method (in this case, SimpleFactory::update()) to redefine the type hint to a valid descendant of the original hint?

一个示例是instanceof运算符,在以下情况下将返回true:

An example would be the instanceof operator, which would return true in the following case:

SimpleAttribute instanceof Attribute // => true

我确实意识到,作为一种变通办法,我可以使类型提示在具体方法中相同,并在方法主体本身中执行instanceof检查,但是是否有一种方法可以在签名级别简单地强制执行此操作?

I do realize that as a work around, I could make the type hint the same in the concrete method, and do an instanceof check in the method body itself, but is there a way to simply enforce this at the signature level?

推荐答案

我不希望如此,因为它可能会破坏类型提示协定.假设函数foo接受了一个AbstractFactory并传递了一个SimpleFactory.

I wouldn't expect so, as it can break type hinting contracts. Suppose a function foo took an AbstractFactory and was passed a SimpleFactory.

function foo(AbstractFactory $maker) {
    $attr = new Attribute();
    $maker->update($attr, 42);
}
...
$packager=new SimpleFactory();
foo($packager);

foo调用update并将一个Attribute传递给工厂,因为AbstractFactory::update方法签名保证它可以采用Attribute,所以应该采用该属性. am! SimpleFactory具有无法正确处理的类型的对象.

foo calls update and passes an Attribute to the factory, which it should take because the AbstractFactory::update method signature promises it can take an Attribute. Bam! The SimpleFactory has an object of type it can't handle properly.

class Attribute {}
class SimpleAttribute extends Attribute {
    public function spin() {...}
}
class SimpleFactory extends AbstractFactory {
    public function update(SimpleAttribute $attr, $data) {
        $attr->spin(); // This will fail when called from foo()
    }
}

在合同术语中,后代类必须遵守其祖先的合同,这意味着函数参数可以获得更多的基础/较少指定/提供更弱的合同,而返回值可以得到更多的派生/指定更多/提供更强的合同.在"埃菲尔教程:继承与契约" ".类型的弱化和加强分别是 contravariance和covariance 的示例.

In contract terminology, descendent classes must honor the contracts of their ancestors, which means function parameters can get more basal/less specified/offer a weaker contract and return values can be more derived/more specified/offer a stronger contract. The principle is described for Eiffel (arguably the most popular design-by-contract language) in "An Eiffel Tutorial: Inheritance and Contracts". Weakening and strengthening of types are examples of contravariance and covariance, respectively.

从理论上讲,这是LSP违反的一个示例.不,不是那个 LSP Liskov替代原理,其中指出可以用子类型的对象代替超类型的对象. SimpleFactoryAbstractFactory的子类型,并且foo接受AbstractFactory.因此,根据LSP,foo应该采用SimpleFactory.这样做会导致调用未定义方法"致命错误,这意味着LSP被违反.

In more theoretical terms, this is an example of LSP violation. No, not that LSP; the Liskov Substitution Principle, which states that objects of a subtype can be substituted for objects of a supertype. SimpleFactory is a subtype of AbstractFactory, and foo takes an AbstractFactory. Thus, according to LSP, foo should take a SimpleFactory. Doing so causes a "Call to undefined method" fatal error, which means LSP has been violated.

这篇关于扩展抽象类时,是否可以将类型提示重新定义为后代类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆