抽象方法中的PHP类型提示接口和方法实现中的类型提示接口的子类 [英] PHP type hint interface in abstract methods and type hint interface's child class in method implementation
问题描述
想象一下我有一个简单的界面:
Imagine I have a simple interface:
interface A {}
然后,我有一些实现该接口的类:
Then, I have some classes implementing that interface:
class B implements A {}
class C implements A {}
然后,我有一个类,该类的方法将类B的对象作为参数(我不能在这里使用接口类型提示,因为只有类B具有类D所需的某些独特功能):
Then, I have a class which have a method which expects object of class B as an argument (I can not use interface type hint here because only class B have some unique features class D requires):
class D
{
public function foo(B $bar) { /*...*/ }
}
但是,我还有另一个具有相同方法的类,现在希望将C类的对象作为参数(我不能在这里使用接口类型提示,因为只有C类具有E类所需的某些独特功能):
But, I also have another class with the same method which now expectes object of class C as an argument (I can not use interface type hint here because only class C have some unique features class E requires):
class E
{
public function foo(C $bar); { /*...*/ }
}
并且必须在其他地方使用类D和E的对象,并且我必须确保这些对象将具有方法foo
,所以我得到了以下(抽象类在这里不是一个错误) ,而不应该使用接口,因为在现实生活中此类也应该包含一些非抽象方法):
And objects of class D and E have to be used somewhere else and I have to make sure that these objects will have method foo
, so I ended up with the following (abstract class is not a mistake here, should not use interface instead, because in real life this class should contain some non-abstract methods too):
abstract class DE
{
abstract public function foo(A $bar); // type-hint interface
}
然后我编辑了我的班级,以便他们扩展班级DE:
Then I edited my classes so they extend class 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
}
在我看来,这段代码在逻辑上是有效的,因为我们可能会在本文中尝试描述这种情况,但是我很惊讶地看到致命错误并显示以下消息: Declaration of of. .必须与..
To my mind this code is logically valid, because we may have situations I tried to describe in this post, but I was surprised to see Fatal error with the message : Declaration of .. must be compatible with ..
所以我的问题如下:如何确保几个对象将具有特定的方法,并且每个对象中的该方法将仅接受特定的对象作为参数?
到目前为止,我看到的唯一解决方法是以下内容(,但我相信对此有更好的解决方案):
As of now, the only workaround I see is something like the following (but I believe there is a better solution for this):
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);
/*...*/
}
}
推荐答案
一个问题是类D和E分别需要具体的类B和C.现在,由于您不应该鼓励类继承,因此我将尽量避免在方法签名中放置具体的类.如果您的班级需要使用具体的班级,请不要泄漏该信息,请将其保密.
One problem is classes D and E requiring concrete classes, B and C respectively. Now since you should be discouraging class inheritance I would avoid putting concrete classes in method signatures as much as I can. If your class needs to use a concrete class don’t leak that information, keep it private.
所以最好有:
public function foo(SomethingAbstract $noIdeaWhatIAmButIDoStuff) {
$concrete = SomethingConcreteThatMakesUseOfAbstract($noIdeaWhatIAmButIDoStuff);
}
than:
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(例如您的示例),那么您就有一个装饰器模式.
If B and C objects need also to implement A (like in your example) then you have a decorator pattern.
这篇关于抽象方法中的PHP类型提示接口和方法实现中的类型提示接口的子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!