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严格标准:Child :: foo()的声明应与第17行/var/www/boludo.PHP中的Base :: foo($arg)兼容
我假设foo($arg)方法在Child类中是不可见的,因为它是私有的.所以,我不是在重载foo,我只是创建一个名为foo的方法.
public function foo($arg = null) {
关于“为什么这不起作用”的问题:
PHP中的可见性严格来说是运行时访问.它不会影响如何扩展/组合/重载类和方法.从子类型中的超类型中松开私有方法的可见性将在子类型中添加单独的方法,而不能访问超类型中的相同命名方法.但是,PHP将为这些提供父子关系.但这并没有引起通知.至少,不是它本身.
您收到通知的原因是您当时也在尝试更改方法签名.你的foo()不再需要$arg传递给它.当您假设方法之间存在父子关系时,这是一个问题,因为Liskov Substitution Principle声明“如果S是T的子类型,则类型T的对象可以用类型S的对象替换”而不会破坏程序.换句话说:如果你有使用Base的代码,你应该能够用Base替换Base,程序应该仍然像使用Base一样工作.
假设你的Base也有一个公共方法栏().
class SomeClientUsingBase { public function doSomethingWithBase(Base $base) { $result = $base->bar(); // …
现在想象Child更改bar()以要求参数.如果您随后将Child for Base传递给客户端,您将破坏客户端,因为客户端调用$base-> bar();没有争论.
显然,您可以更改客户端以传递参数,但是代码实际上取决于Child如何定义方法,因此Typehint是错误的.事实上,Child并不是Base,因为它的行为不像Base.那时它的遗传就破了.
现在有趣的是,如果你从foo()中删除那个$arg,你在技术上不会违反LSP,因为客户端仍然会工作.通知在这里是错误的.在以前使用Base的客户端中调用$base-> foo(42)仍然可以使用Child,因为Child可以简单地忽略该参数.但PHP希望你使参数可选.
请注意,LSP也适用于方法可能返回的内容. PHP只是在签名中不包含返回类型,因此您自己考虑了这一点.您的方法必须返回Supertype返回的内容或行为上相同的内容.