为什么重写方法参数违反了PHP中的严格标准?

Kae*_*one 41 php oop

我知道StackOverflow中有类似问题,就像这个问题一样.

为什么重写方法参数违反了PHP中的严格标准?例如:

class Foo
{
    public function bar(Array $bar){}
}

class Baz extends Foo
{
    public function bar($bar) {}
}
Run Code Online (Sandbox Code Playgroud)

严格的标准:Baz :: bar()的声明应该与Foo :: bar()的声明兼容

在其他OOP编程语言中,您可以.为什么PHP不好?

Tiv*_*vie 51

在OOP中,SOLID代表单一责任,开放式封闭,Liskov替换,接口隔离和依赖性反转.

Liskov替换原则指出的是,在一个计算机程序中,如果酒吧是的子类型的Foo,然后类型的对象的Foo可以与类型的对象替换酒吧而不改变任何节目的期望的性质(正确性,执行任务等的).

在强类型编程语言中,当覆盖Foo方法时,如果更改Bar中的签名,则实际上是在重载,因为原始方法和新方法可用于不同的签名.由于PHP是弱类型的,因此无法实现,因为编译器无法知道您实际调用的是哪种方法.(因此,即使他们的签名不同,您也不能拥有2个具有相同名称的方法).

因此,为了避免违反Liskov Substituition原则,会发出严格的标准警告,告诉程序员由于子类中方法签名的更改而可能会出现问题.

  • 我不得不在这里不同意两件事:"如果Bar是Foo的子类型,那么Foo类型的对象可以用Bar类型的对象替换(反之亦然)".反之亦然部分不成立; 你不希望在任何使用sublcass的地方使用超类.另一件事是关于LSP:如果参数是逆变的,那么类型是受到尊重的.如果PHP是纯粹的OO那么就没有问题,因为Array会比Object更窄(假设声明中没有类型意味着任何对象).因此bar()的实现在Baz中更为通用,使其适合LSP (22认同)
  • @KaernStone LSP不适用于Ctors,因为这会限制多态性.不同的子类型可能需要不同的依赖关系.想想"Log"和子类型"DbLogger"和"FileLogger". (4认同)
  • @Tivie:拜托,请不要接受这个,但我认为这样的答案是误导性的.我会贬低它. (3认同)
  • 非常好的解释,谢谢.那为什么我可以在构造函数中打破Liskov原则呢? (2认同)
  • @AndrésFortier"因此bar()的实现在Baz中更为通用,使其适合LSP".一个子类只能更具体,而不是更一般.此外,您还有其他声明"LSP应该始终存在,构造函数不应该是特例".可以解释.构造函数不必遵守LSP的原因是新对象的创建永远不可互换.即使你把它放在工厂方法中,你要么创建A,要么最后创建B. 对象创建中没有多态性. (2认同)

Dev*_*ris 18

我知道我迟到了,但答案并没有真正说明实际问题.

问题是PHP不支持函数/方法重载.在无类型语言中支持函数重载是很困难的.

提示有帮助.但在PHP中它非常有限.不知道为什么.例如,您不能提示变量是int或Boolean但数组是正常的.去搞清楚!

其他面向对象的语言使用函数重载来实现这一点.也就是说功能的签名明显不同.

因此,例如,如果以下可能,我们就不会有问题

class Foo
{
    public function bar(Array $bar){
        echo "Foo::bar";
    }
}

class Baz extends Foo
{
    public function bar(int $bar) {
        echo "Baz::bar";
    }
}


$foo = new Baz();
$bar = new Baz();
$ar = array();
$i = 100;

$foo->bar($ar);
$bar->bar((int)$i);

would output

Foo::bar
Baz::bar
Run Code Online (Sandbox Code Playgroud)

当然,当涉及构造函数时,php开发人员意识到他们必须实现它,无论喜欢与否!因此,他们只是在第一种情况下抑制错误或不提高错误.

哪个很傻.

熟人曾经说PHP实现的对象只是一种实现名称空间的方式.现在我并不是那么重要,但是所做的一些决定确实倾向于支持这一理论.

在开发代码时我始终会打开最大警告,我从不会在不了解其含义和含义的情况下发出警告.我个人不关心这个警告.我知道自己想做什么,而PHP却做得不对.我来到这里寻找一种有选择地抑制它的方法.我还没有找到办法.

所以我会抓住这个警告并自己压制它.惭愧我需要这样做.但我对STRICT很严格.

  • 关于构造函数,在PHP 5.4+中,方法签名在扩展_abstract_基类时必须兼容,否则会出现致命错误.有点奇怪,在PHP 5.4之前甚至没有E_STRICT警告,如果基类不是抽象的,那么无论PHP版本如何都没有消息. (2认同)