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“应该”是“不是”的“实例”吗?