如何在 PHP 中的子类继承方法中定义更严格的类型? [英] How to define stricter typing in child class inherited methods in PHP?

查看:59
本文介绍了如何在 PHP 中的子类继承方法中定义更严格的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有三个这样的类.

Assume I have three classes like so.

abstract class A {
   abstract protected function doSomething($object): array;
}

class B extends A {
   protected function doSomething(SomeObject $object): array
   {
       // something
   }
}

class C extends A {
   protected function doSomething(OtherObject $object): array
   {
       // something
   }
}

根据 PHP 的继承原则,上述结构不是合法的 PHP 代码,因为方法定义与基类不兼容.我当然可以做类似的事情

According to principles of inheritance as PHP does it, the structure described above is not legal PHP code, as the method definitions are not compatible with the base class. I can, of course, do something like

class B extends A {
    protected function doSomething($object): array
    {
        if (!is_a($object, 'SomeObject')) {
            throw new Exception('Object passed to method is not of the correct class for this method.');
        }

        // something
    }
}

但我想知道是否有另一种解决方案来实现抽象类中的方法,该方法可以重新定义为仅接受其中特定类型的对象.

But I was wondering if there is another solution to implementing a method in an abstract class that can be redefined to only accept objects of specific type in it.

推荐答案

您不能不以与您的示例类似的方式自己实现它.

You can't without implementing it yourself in similar way than in your example.

PHP 对协变和逆变的支持 明确定义:

PHP support for covariance and contravariance is clearly defined:

协方差允许子方法返回比其父方法的返回类型更具体的类型.然而,逆变允许子方法中的参数类型比其父方法中的参数类型更不具体.

Covariance allows a child's method to return a more specific type than the return type of its parent's method. Whereas, contravariance allows a parameter type to be less specific in a child method, than that of its parent.

如果子类能够拥有比其父类或接口更严格的参数要求,这将导致预期落空.

If a child class were capable of having stricter parameter requirements than its parent or interface, this would lead to broken expectations.

例如:假设您有以下内容:

For example: let's say that you have the following:

abstract class AbstractParam{}

class ParamOne extends AbstractParam{}
class ParamTwo extends AbstractParam{}
class ParamThree extends AbstractParam{}

abstract class AbstractService {

    abstract public function foo(AbstractParam $bar);
}

任何时候您需要使用此服务的实现时,您都可以确保将 AbstractParam 的任何有效实例传递给 foo()合法的.方法签名清楚地传达了这一点.

Any time you would need to use an implementation of this service, you would do so with the assurance that passing any valid instance of AbstractParam to foo() would be legal. The method signature is clearly communicating this.

如果我可以在继承/实现上改变这一点,突然间我可以将 foo() 签名更改为:

If I could change this on inheritance/implementation, and suddenly I could change foo() signature to:

public function foo(ParamOne $bar)

契约会被破坏,你不能安全地依赖 AbstractService,因为不再可能将任何 AbstractParam 实例传递给 foo(),因此在过程中违反LSP:你不能再替代基类的对象以及属于该基对象子类型的对象,同时保持正确性.

The contract would be broken, and you couldn't depend on AbstractService safely, since there would be no longer possible to pass any AbstractParam instance to foo(), thus violating the LSP in the process: You could no longer substitute objects of the base class with objects that belong to a subtype of that base object while maintaining correctness.

您问题中的方法可行,但由于上述原因,我认为这不是一个很好的设计.如果您真的必须这样做,只需从方法定义中删除类型提示:

The approach in your question would work, but I don't think it's a great design for the above reasons. If you really must go that way, simply remove the type hint from method definition:

abstract class AbstractService {

    abstract public function foo($bar);
}

class ConcreteService extends AbstractService {
    public function foo($bar) {}
}

但最好重新考虑一下您为什么真正需要它,并尝试保留类型安全性.

But it's probably better to rethink why you actually need this, and try to retain type-safety.

这篇关于如何在 PHP 中的子类继承方法中定义更严格的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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