42

我知道 StackOverflow 中有几个类似的问题,比如这个问题

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

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

class Baz extends Foo
{
    public function bar($bar) {}
}

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

在其他 OOP 编程语言中你可以。为什么 PHP 不好?

4

4 回答 4

55

在 OOP 中,SOLID代表单一责任、开放封闭、里氏替换、接口隔离和依赖倒置

Liskov 替换原则指出,在计算机程序中,如果BarFoo的子类型,则Foo类型的对象可以用Bar类型的对象替换,而不会改变该程序的任何所需属性(正确性、执行的任务等)。 )。

在强类型编程语言中,当重写 Foo 方法时,如果您更改 Bar 中的签名,您实际上是在重载,因为原始方法和新方法具有不同的签名。由于 PHP 是弱类型的,这是不可能实现的,因为编译器无法知道您实际调用了哪些方法。(因此你不能有两个同名的方法,即使它们的签名不同)。

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

于 2012-11-16T20:03:44.363 回答
17

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

问题是 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

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

这是愚蠢的。

一位熟人曾经说过 PHP 实现对象只是作为实现命名空间的一种方式。现在我并不那么挑剔,但做出的一些决定确实倾向于支持该理论。

在开发代码时,我总是打开最大的警告,我从来没有在不了解它的含义和含义的情况下放过警告。就我个人而言,我不关心这个警告。我知道我想做什么,而 PHP 做的不对。我来这里是为了寻找一种选择性抑制它的方法。我还没有找到方法。

所以我会捕获这个警告并自己压制它。可惜我需要这样做。但我对 STRICT 很严格。

于 2013-10-15T06:42:53.250 回答
4

您可以覆盖参数,但签名应该匹配。如果你Array在前面放出来$bar,就没有问题了。

例如,如果您添加了一个附加参数,那么只要第一个参数具有相同的类型提示,就没有问题。这是任何语言的好习惯。

于 2012-11-16T19:57:33.800 回答
2

因为您声明的Foo应该$bar是 type array,而在 extended 中Bar$bar没有声明 's 的类型。

这不是错误,而是警告。您应该使方法定义与原始基类兼容。但是,如果您知道自己在做什么,则可以安全地忽略它(并且只有在您知道自己在做什么的情况下!!!)

于 2012-11-16T19:58:07.567 回答