PHP接口实现拒绝参数上的子类

PHP接口实现拒绝参数上的子类,php,interface,subclass,type-hinting,interface-implementation,Php,Interface,Subclass,Type Hinting,Interface Implementation,考虑这一点: class A{} class B extends A{} interface I{ // expects object instanceof A function doSomething(A $a); } class C implements I { // fails ???? function doSomething(B $b){} } 在我的概念中,上面的方法应该是有效的,但它不能,因为php拒绝要求第一个参数与接口(I)中定义的类型(A)完全相同的实现。因为

考虑这一点:

class A{}

class B extends A{}

interface I{
 // expects object instanceof A
 function doSomething(A $a);
}

class C implements I
{
 // fails ????
 function doSomething(B $b){}
}

在我的概念中,上面的方法应该是有效的,但它不能,因为php拒绝要求第一个参数与接口(I)中定义的类型(A)完全相同的实现。因为B是a的一个子类,我不知道有什么问题。我在这里遗漏了什么吗?

类C实现了I
意味着
C
I
之间必须存在子类型关系。这意味着
C
类型的对象应该在需要
I
类型的对象时可用

在您的例子中,
C
I
更具限制性,因为它对
doSomething
参数有更精确的要求--
I.doSomething
适用于任何
A
,但
C.doSomething
需要
A
的特定子类型

请注意,如果您将
C.doSomething
更改为接受任何
A
,则不会阻止您向其传递类型为
B
的对象。您不能只要求
B
,因为这样您将破坏子类型合同

理论上,子类型可以更自由地定义其函数参数,更具体地定义其返回类型(但决不能像您的情况那样,反之亦然)。实际上,编程语言可能要求重写方法中的参数类型在任何地方都必须相同

从理论上讲,子类型可以更自由地处理其函数参数 以及更具体的返回类型(但决不能相反,如下所示) 就你的情况而言)。实际上,编程语言可能需要 重写方法中的参数类型在任何地方都必须相同

解决此问题的方法很少—
instanceof

class A{}

class B extends A{}

interface I{
 // expects object instanceof A
 function doSomething(A $a);
}

class C implements I
{

 function doSomething(A $b){
   if($b is instance of B){
   //do something
   }else{throw new InvalidArgumentException("arg must be instance of B") };
 }
}

嗯,
B
A
的后代,但不等于,PHP对这一点的看法是严格的。就是这样,我不认为有可能解决这个问题——你可能只需要在没有hintIt不起作用的情况下工作。参见示例2。Liskov替换原则:如果
B
扩展了
A
,那么
C::doSometing()
就没有理由只接受
B
,而不是所有
A
类型的对象。@Mchl我同意从逻辑上讲,你会认为它应该工作,但不幸的是,它在PHP中并不存在。@Wiseguy:我的观点是PHP完全正确地拒绝了这个定义。你答案的第二段解释了我需要知道的一切。谢谢。
C
如何比
I
更具限制性,如果
B
实现了
A
的所有功能,然后是一些功能?@Cypher——如果
B
实现了
A
的所有功能,然后是一些功能,那么它比
A
更强大,因此,
C
doSomething
需要比
I
doSomething
更有力的论证(它满足于一个“仅仅”的
a
。换句话说,
C
doSomething
I
doSomething
更挑剔。should“应该”是“不是”的“实例”吗?