我有这个测试脚本:
<?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();
Run Code Online (Sandbox Code Playgroud)
这运行良好和输出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();
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
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
Run Code Online (Sandbox Code Playgroud)
为什么这首次在第一次工作?我希望在这两种情况下出现错误......
使用接口时,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>();
}
Run Code Online (Sandbox Code Playgroud)
更具体地说:
if ($obj instanceof A) {
$obj->myfunction();
}
Run Code Online (Sandbox Code Playgroud)
由于A::myfunction规范地声明为不接受任何参数,因此上面的代码将始终有效。但是,如果没有接口:
if ($obj instanceof B) {
$obj->myfunction('foo');
}
Run Code Online (Sandbox Code Playgroud)
如果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');
}
Run Code Online (Sandbox Code Playgroud)
C既是instanceof A又是B,但它不能myfunction同时与 的两种实现兼容。这是创建两个冲突的实现的问题。PHP 是否也应该在这里发出警告是有争议的。PHP 不能鱼与熊掌兼得。它的类型系统可以帮助您尽早发现某些错误;它当然并不完美,并且无法保护您免于从所有可能的角度射中自己的脚。
如果您想避免此类问题,您基本上不应该更改方法签名。或者让变化向下级联;这意味着每个扩展类与其直接父类的方法签名兼容。因此C::myfunction应该接受至少一个可选参数。也许 PHP 应该捕获这种情况,也许它可以被视为一个错误,即您在所有情况下都没有收到警告。同样,这是有争议的,您应该从一开始就避免陷入这种情况。
| 归档时间: |
|
| 查看次数: |
462 次 |
| 最近记录: |