考虑一下:
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的子类,我看不出问题是什么。我在这里错过了什么吗?
答案 0 :(得分:5)
class C implements I
表示C
和I
之间必须存在子类型关系。这意味着类型C
的对象应该可以在需要I
类型的对象的任何地方使用。
在您的情况下,C
比I
更具限制性,因为它对doSomething
参数有更精确的要求 - I.doSomething
对任何A
都可以。但C.doSomething
需要A
请注意,如果您将C.doSomething
更改为接受任何A
,则不会阻止您将B
类型的对象传递给它。你不能只需要B
,因为那样你就会破坏子类型合同。
理论上,子类型对于它们的函数参数可以更自由,并且对于它们的返回类型更具体(但反之亦然,就像在你的情况下一样)。实际上,编程语言可能要求重写方法中的参数类型必须在任何地方都相同。
答案 1 :(得分:2)
理论上,子类型对其函数参数可以更自由 并且更具体地说明他们的回归类型(但反之亦然) 这是你的情况)。实际上,编程语言可能需要 重写方法中的参数类型必须在任何地方都相同。
解决这个问题的工作很少 - 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") };
}
}