为什么PHP中的LSP违规有时是致命的,有时是警告?

bis*_*hop 7 php liskov-substitution-principle

此LSP违规会引发致命错误:

abstract class AbstractService { }
abstract class AbstractFactory { abstract function make(AbstractService $s); }
class ConcreteService extends AbstractService { }
class ConcreteFactory extends AbstractFactory { function make(ConcreteService $s) {} }
Run Code Online (Sandbox Code Playgroud)

此LSP违规也会引发致命错误:

interface AbstractService { }
interface AbstractFactory { function make(AbstractService $s); }
class ConcreteService implements AbstractService { }
class ConcreteFactory implements AbstractFactory { function make(ConcreteService $s) {} }
Run Code Online (Sandbox Code Playgroud)

虽然这种LSP违规只会引发警告:

class Service { }
class Factory { function make(Service $s) {} }
class MyService extends Service { }
class MyFactory extends Factory { function make(MyService $s) {} }
Run Code Online (Sandbox Code Playgroud)

为什么?它们不应该都是致命的,因为它们都是逆变的吗?

jsz*_*ody 8

在第一种情况下,这是一个致命的错误,因为PHP要求您与父抽象类兼容:

从抽象类继承时......方法的签名必须匹配.

同样如此在第二种情况:

实现接口的类必须使用与接口中定义的完全相同的方法签名.不这样做会导致致命错误.

在第三种情况下,您扩展了普通的PHP类,而不是抽象的.PHP允许您更改签名,尽管有警告.

这显然不是一个好习惯,并且如你所指出的那样违反了LSP.这只是PHP为您提供尖锐物体的众多方式之一,如果您不小心,会让您自己受伤.=)

如果要强制执行LSP,则需要使用接口,抽象或final在父类中创建方法.

以下是一个示例final:https://3v4l.org/s42XG