在PHP中"重载"一个私有方法

Enr*_*cos 9 php oop overloading

我知道我不能在PHP中重载方法.而且,据我所知,private类中的方法对于扩展基类的类是不可见的.那为什么这不起作用?

class Base {
  private function foo($arg) {
     print "Base $arg";
  }
}

class Child extends Base {
  public function foo() {
     print "Child";
  }
}

$c = new Child;
print $c->foo();
Run Code Online (Sandbox Code Playgroud)

错误:

PHP Strict Standards: Declaration of Child::foo() should be compatible with Base::foo($arg) in /var/www/boludo.php on line 17

我认为该foo($arg)方法在Child课堂上是不可见的,因为是private.所以,我没有超载foo,我只是创建一个名为的方法foo.

Gor*_*don 3

要修复该通知,只需将foo()Child 更改为

\n\n
public function foo($arg = null) {\n
Run Code Online (Sandbox Code Playgroud)\n\n

至于“为什么这不起作用”的问题:

\n\n

PHP 中的可见性严格与运行时访问有关。它不会影响您如何扩展/组合/重载类和方法。放宽子类型中超类型的私有方法的可见性将在子类型中添加一个单独的方法,而无法访问超类型中的相同命名方法。然而,PHP 将假定它们之间存在父子关系。但这并没有引起通知。至少,不是靠它自己。

\n\n

您收到通知的原因是您还尝试更改方法签名。您foo()不再需要$arg传递给它。当您假设方法之间存在父子关系时,这是一个问题,因为里氏替换原则指出“如果 S 是 T 的子类型,则类型 T 的对象可以替换为类型 S 的对象”,而不会破坏程序。换句话说:如果您有使用 的代码Base,您应该能够替换BaseChild,并且程序应该仍然像使用 一样工作Base

\n\n

假设你Base还有一个公共方法bar()

\n\n
class SomeClientUsingBase\n{\n    public function doSomethingWithBase(Base $base)\n    {\n        $result = $base->bar();\n        // \xe2\x80\xa6\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在想象一下需要争论的Child变化。bar()如果您随后将Childfor传递Base给客户端,则会破坏客户端,因为客户端调用时$base->bar();不带参数。

\n\n

显然,您可以更改客户端以传递参数,但是代码实际上取决于Child方法的定义方式,因此 Typehint 是错误的。事实上,Child不是Basethen,因为它的行为不像Base. 那么继承就被打破了。

\n\n

现在有趣的是,如果你$arg从 中删除它foo(),从技术上讲你并没有违反 LSP,因为客户端仍然可以工作。这里的通知是错误的。调用$base->foo(42)以前使用过的客户端Base仍然可以使用 a Child,因为 aChild可以简单地忽略该参数。但 PHP 希望您将参数设置为可选。

\n\n

请注意,LSP 也适用于方法可能返回的内容。PHP 只是不在签名中包含返回类型,因此您必须自己考虑这一点。您的方法必须返回超类型返回的内容或行为等效的内容。

\n