使用具体类型的接口类型提示实现抽象方法

时间:2014-11-06 15:08:12

标签: php

这是一个我无法解释的简单问题。

在PHP手册中:

  

如果将类或接口指定为类型提示,则也允许其所有子项或实现。

我记住,它是抽象方法的情况,但在我看来似乎没有逻辑"。

以下是一个例子:

我通过这种方式搜索如何实现一个方法(在这个例子中,调用):

<?php
namespace Foo\Bundle\BarBundle;

abstract class BaseClass {

    //...

    abstract public function invoke(AddContactCommandInterface $command);
}

<?php
namespace Foo\Bundle\UpBarBundle;

use Foo\Bundle\BarBundle\BaseClass;

class UpClass extends BaseClass
{
    public function invoke(AddContactCommand $command)
    {
        //...
    }
}

AddContactCommand实现AddContactCommandInterface!

我有这个问题

  

声明必须与BaseClass-&gt; invoke(AddContactCommandInterface)兼容

有人可以向我解释为什么在PHP 5.6中无法进行这种基本和逻辑操作?

3 个答案:

答案 0 :(得分:2)

抽象方法定义了一个所有派生类需要实现的函数。在定义抽象方法时,您说它需要AddContactCommandInterface,然后在您的子类中将其更改为AddContactCommand。您正在更改Abstract类中指定的“合同”。

AddContactCommand实现接口并不重要。并非所有AddContactCommandInterfaces都是AddContactCommands

从使用的角度来看,如果允许这样做会导致困难,因为我可能有一个期望使用BaseClass对象的方法。我有一个实现Foo的不同对象AddContactCommandInterface。现在我的方法获取了UpClass的实例,并尝试使用传递在我的invoke对象中的Foo方法。这将导致致命错误,即使从我对Abstract类中指定的合同的理解,我应该能够使用我的Foo对象。随之而来的是混乱和大规模的歇斯底里。

这不是逻辑问题,而是一致性问题。如果您确实要键入提示AddContactCommand,请更改抽象方法。但是如果您打算可以使用实现AddContactCommandInterface的所有内容,那么请更改派生类。

答案 1 :(得分:1)

BaseClass声明任何子类都必须有一个名为invoke的公共方法,它接受任何实现AddContactCommandInterface的对象。

UpClass并未满足此要求。 它的invoke函数只接受AddContactCommand或子对象的具体实例。

如果允许您的代码,以下内容将失败:

class SomeOther implements AddContactCommandInterface
{
    //implementation of interface
}

$up = new UpClass();
$up->invoke(new SomeOther());

为什么不让UpClass->invoke接受接口的实现?您仍然可以传递具体的AddContactCommand

答案 2 :(得分:0)

在你的第二堂课中,你将覆盖BaseClass; s invoke方法---

这要求子类中的invoke方法接受相同的参数 -

在这种情况下,你有类型暗示争论者$command的类型为AddContactCommandInterface ---但是,在你的子类中,你创建了参数AddContactCommand

因此,您可以通过使基类中的$command与子类中的$command类型相同来修复它,反之亦然。