使用不兼容的函数实现接口和错误

时间:2014-05-09 07:29:45

标签: php oop

我有这个测试脚本:

<?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

为什么这首次在第一次工作?我希望在这两种情况下出现错误......

1 个答案:

答案 0 :(得分:3)

使用界面时,BC会根据界面声明进行独立验证。 C extends B并不重要。 C间接implements AC::myfunctionA::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应该抓住这个案例,也许它可能被认为是一个你在所有情况下都没有收到警告的错误。同样,这是有争议的,你应该避免开始这种情况。