为什么 PHP 中的 LSP 违规有时是致命的,有时是警告?
Why are LSP violations in PHP sometimes fatal, and sometimes warnings?
此 LSP 违规 raises a Fatal Error:
abstract class AbstractService { }
abstract class AbstractFactory { abstract function make(AbstractService $s); }
class ConcreteService extends AbstractService { }
class ConcreteFactory extends AbstractFactory { function make(ConcreteService $s) {} }
此 LSP 违规 also raises a Fatal Error:
interface AbstractService { }
interface AbstractFactory { function make(AbstractService $s); }
class ConcreteService implements AbstractService { }
class ConcreteFactory implements AbstractFactory { function make(ConcreteService $s) {} }
虽然此 LSP 违规仅 raises a Warning:
class Service { }
class Factory { function make(Service $s) {} }
class MyService extends Service { }
class MyFactory extends Factory { function make(MyService $s) {} }
为什么?因为它们都是逆变的,所以它们不应该都是致命的吗?
第一种情况是致命错误,因为PHP requires you to be compatible with a parent abstract class:
When inheriting from an abstract class... signatures of the methods must match.
第二种情况下的same is true:
The class implementing the interface must use the exact same method signatures as are defined in the interface. Not doing so will result in a fatal error.
在第三种情况下,你扩展了一个普通的PHP class,而不是抽象的。 PHP 允许您更改签名,但会出现警告。
这显然不是一个好的做法,并且正如您指出的那样确实违反了 LSP。只是 PHP 给你尖锐物体的众多方式之一,如果你不小心,就会伤到自己。 =)
如果你想强制执行 LSP,你需要使用一个接口,抽象,或者在父 class.
中创建你的方法 final
这是 final
的示例:https://3v4l.org/s42XG
2019 年 5 月,LSP errors RFC 更新了语言。从 PHP 8 开始,引擎将 总是 为不兼容的方法签名生成 致命错误。
在此更改之前,派生的 class 可以更改签名 willy-nilly,忽略错误并继续。不再:classes,就像abstract class
和interface
必须遵守LSP。
此 LSP 违规 raises a Fatal Error:
abstract class AbstractService { }
abstract class AbstractFactory { abstract function make(AbstractService $s); }
class ConcreteService extends AbstractService { }
class ConcreteFactory extends AbstractFactory { function make(ConcreteService $s) {} }
此 LSP 违规 also raises a Fatal Error:
interface AbstractService { }
interface AbstractFactory { function make(AbstractService $s); }
class ConcreteService implements AbstractService { }
class ConcreteFactory implements AbstractFactory { function make(ConcreteService $s) {} }
虽然此 LSP 违规仅 raises a Warning:
class Service { }
class Factory { function make(Service $s) {} }
class MyService extends Service { }
class MyFactory extends Factory { function make(MyService $s) {} }
为什么?因为它们都是逆变的,所以它们不应该都是致命的吗?
第一种情况是致命错误,因为PHP requires you to be compatible with a parent abstract class:
When inheriting from an abstract class... signatures of the methods must match.
第二种情况下的same is true:
The class implementing the interface must use the exact same method signatures as are defined in the interface. Not doing so will result in a fatal error.
在第三种情况下,你扩展了一个普通的PHP class,而不是抽象的。 PHP 允许您更改签名,但会出现警告。
这显然不是一个好的做法,并且正如您指出的那样确实违反了 LSP。只是 PHP 给你尖锐物体的众多方式之一,如果你不小心,就会伤到自己。 =)
如果你想强制执行 LSP,你需要使用一个接口,抽象,或者在父 class.
中创建你的方法final
这是 final
的示例:https://3v4l.org/s42XG
2019 年 5 月,LSP errors RFC 更新了语言。从 PHP 8 开始,引擎将 总是 为不兼容的方法签名生成 致命错误。
在此更改之前,派生的 class 可以更改签名 willy-nilly,忽略错误并继续。不再:classes,就像abstract class
和interface
必须遵守LSP。