我有这个测试脚本:
<?php
interface A
{
function myfunction();
}
class B implements A
{
function myfunction($var = "default")
{
echo $var;
}
}
class C extends B
{
function myfunction()
{
echo "myfunction";
}
}
$c = new C();
$c->myfunction();
$b = new B();
$b->myfunction();
运行正常并输出myfunctiondefault
。
现在当我删除界面A并让B不再实现A时,就像这样:
<?php
class B
{
function myfunction($var = "default")
{
echo $var;
}
}
class C extends B
{
function myfunction()
{
echo "myfunction";
}
}
$c = new C();
$c->myfunction();
$b = new B();
$b->myfunction();
我收到此错误:
PHP Strict standards: Declaration of C::myfunction() should be compatible with that of B::myfunction() in /var/www/test/index.php on line 16
Strict standards: Declaration of C::myfunction() should be compatible with that of B::myfunction() in /var/www/test/index.php on line 16
myfunctiondefault
为什么这首次在第一次工作?我希望在这两种情况下出现错误......
答案 0 :(得分:3)
使用界面时,B
和C
会根据界面声明进行独立验证。 C extends B
并不重要。 C
间接implements A
,C::myfunction
与A::myfunction
兼容,所以没问题。 B::myfunction
也与A::myfunction
兼容,因此也没问题。
如果没有接口,B::myfunction
是该方法的规范声明,并且由于它接受参数但覆盖C::myfunction
没有,因此会引发STRICT
警告。
基本上,您需要确保此代码有效:
if ($obj instanceof <classWhoseInterfaceIExpect>) {
$obj-><interfaceIExpect>();
}
更具体地说:
if ($obj instanceof A) {
$obj->myfunction();
}
由于A::myfunction
被规范地声明为不接受任何参数,因此上述代码将始终有效。但是,没有界面:
if ($obj instanceof B) {
$obj->myfunction('foo');
}
如果B::myfunction
是接受参数的规范声明,但是C
提供的实现没有,那么您就会产生冲突。因此警告。这是为了回答问题为什么它的工作方式,这是PHP的思想解释。
警告:是的,即使你使用界面,这仍会产生同样的冲突:
interface A { ... }
class B implements A { ... }
class C extends B { ... } // conflicting implementation to B
$obj = new C;
if ($obj instanceof B) {
$obj->myfunction('foo');
}
C
既是instanceof
A
又是B
,但它同时与myfunction
的两种实现都不兼容。这是创建两个冲突实现的问题。 PHP 是否应在此处发出警告是值得商榷的。 PHP不能吃你的蛋糕也吃。它的类型系统可以帮助您尽早发现某些错误;它肯定不是完美的,不能保护你不受任何可能的角度拍摄自己的脚。
如果您想避免此类问题,您基本上不应该更改方法签名。那,或者让变化向下级联;意味着每个扩展类都与其直接父类的方法签名兼容。因此C::myfunction
应该接受至少一个可选参数。也许PHP应该抓住这个案例,也许它可能被认为是一个你在所有情况下都没有收到警告的错误。同样,这是有争议的,你应该避免开始这种情况。