抽象方法中的PHP类型提示接口和方法实现中的类型提示接口的子类

时间:2015-10-20 18:36:06

标签: php oop

想象一下,我有一个简单的界面:

interface A {}

然后,我有一些实现该接口的类:

class B implements A {}
class C implements A {}

然后,我有一个类,它有一个方法,它希望将类B的对象作为参数(我不能在这里使用接口类型提示,因为只有类B具有D类所需的一些独特特性):

class D
{
    public function foo(B $bar) { /*...*/ }
}

但是,我还有另一个使用相同方法的类,现在将类C的对象作为参数(我不能在这里使用接口类型提示,因为只有类C具有类E要求的一些独特功能):

class E
{
    public function foo(C $bar); { /*...*/ }
}

D类和E类的对象必须在其他地方使用,我必须确保这些对象具有方法foo,所以我最终得到了以下(抽象类不是这里的错误,不应该使用接口,因为在现实生活中这个类应该包含一些非抽象的方法)

abstract class DE
{
    abstract public function foo(A $bar); // type-hint interface
}

然后我编辑了我的类,因此他们扩展了类DE:

class D extends DE 
{
    public function foo(B $bar); // class B implements A
}

class E extends DE 
{
    public function foo(C $bar); // class C implements A
}

在我看来,这段代码在逻辑上是有效的,因为我们可能会遇到我在本文中试图描述的情况,但我很惊讶地看到致命错误,其中包含以下消息:声明。 。必须与..

兼容

所以我的问题如下:如何确保多个对象具有特定方法,并且每个对象中的方法仅接受特定对象作为参数?

截至目前,我看到的唯一解决方法是以下内容(但我相信有更好的解决方案):

interface A {}
class B implements A {}
class C implements A {}

interface DE 
{
    public function foo(A $bar);
}

class D implements DE 
{
    public function foo(A $bar) 
    {
        assert($bar instanceof B);
        /*...*/
    }
}

class E implements DE 
{
    public function foo(A $bar)
    {
        assert($bar instanceof C);
        /*...*/
    }
}

1 个答案:

答案 0 :(得分:2)

一个问题是D类和E类分别需要具体的类B和C.既然你应该劝阻类继承,我会尽量避免在方法签名中放入具体的类。如果您的类需要使用具体类,请不要泄漏该信息,请将其保密。

所以最好有:

public function foo(SomethingAbstract $noIdeaWhatIAmButIDoStuff) {
    $concrete = SomethingConcreteThatMakesUseOfAbstract($noIdeaWhatIAmButIDoStuff);
}

比:

public function foo(SomethingConcrete $tmi) {

}

我建议按照以下思路思考:

abstract class DE {

    public abstract function foo(A $a);

}

class D extends DE {

    public function foo(A $a) {
        $b = new B($a);
        //do with $b what you please
    }

}

class E extends DE {

    public function foo(A $a) {
        $c = new C($a);
        //now you can use $c which will leverage $a
    }

}

如果B和C对象也需要实现A(就像你的例子中那样)那么你就有了装饰模式。