我知道我无法在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();
错误:
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
。
要修正此通知,只需将foo()
“子项”更改为
public function foo($arg = null) {
关于“为什么这不起作用”的问题:
PHP中的可见性完全是关于运行时访问的。它不会影响您如何扩展/组成/重载类和方法。从子类型的父类型中松开私有方法的可见性将在子类型中添加单独的方法,而无法访问父类型中的相同命名方法。但是,PHP将为此假定一个父子关系。但这并没有引起通知。至少不是一个人。
之所以收到通知,是因为您随后还试图更改方法签名。您foo()
不再需要$arg
将其传递给它。当您假定方法之间的父子关系时,这是一个问题,因为《里斯科夫替代原理》指出:“如果S是T的子类型,则T类型的对象可以用S类型的对象替换”而不会破坏程序。换句话说:如果您有使用的代码,则Base
应该可以将其替换Base
为Child
并且该程序应仍像使用一样正常工作Base
。
假设您Base
也有一个公共方法bar()
。
class SomeClientUsingBase
{
public function doSomethingWithBase(Base $base)
{
$result = $base->bar();
// …
现在想象需要参数的Child
更改bar()
。如果随后将其传递Child
给Base
客户端,则将断开客户端,因为客户端在调用时$base->bar();
不带参数。
显然,您可以更改客户端以传递参数,但是代码实际上取决于Child
方法的定义方式,因此Typehint是错误的。实际上,Child
不是一个Base
then,因为它的行为不像Base
。然后,它是残缺的继承。
现在有趣的是,如果$arg
从中删除它,从foo()
技术上讲,您不会违反LSP,因为客户端仍然可以工作。该通知在这里是错误的。调用$base->foo(42)
以前使用过的客户端Base
仍然可以使用,Child
因为Child
可以简单地忽略该参数。但是PHP希望您随后将参数设为可选。
请注意,LSP也适用于方法可能返回的内容。PHP只是在签名中不包含返回类型,因此您自己考虑了这一点。您的方法必须返回Supertype返回的内容或行为上等效的内容。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句