Why are LSP violations in PHP sometimes fatal and sometimes warnings?

This LSP violation causes 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) {} } 

This LSP violation also causes a fatal error :

 interface AbstractService { } interface AbstractFactory { function make(AbstractService $s); } class ConcreteService implements AbstractService { } class ConcreteFactory implements AbstractFactory { function make(ConcreteService $s) {} } 

While this LSP violation raises a warning :

 class Service { } class Factory { function make(Service $s) {} } class MyService extends Service { } class MyFactory extends Factory { function make(MyService $s) {} } 

Why? Aren't they all deadly because they are all contravariant?

+7
php lsp liskov-substitution-principle
source share
2 answers

In the first case, this is a fatal error, because PHP requires you to be compatible with the parent abstract class :

When inheriting from an abstract class ... method labels must match.

the same is true in the second case:

A class that implements the interface must use the same method signatures that are defined in the interface. This will not result in a fatal error.

In the third case, you are distributing a regular PHP class, not an abstract one. PHP allows you to change the signature, albeit with a warning.

This is obviously not a good practice and violates the LSP when you specify. Only one of the many ways PHP gives you sharp objects and allows you to harm yourself if you are not careful. =)

If you want the LSP to be enforced, you need to use an interface abstract or make your final method in the parent class.

Here is a final example: https://3v4l.org/s42XG

+8
source share

In May 2019, LSP RFC errors updated the language. Starting with PHP 8, the mechanism will always generate a fatal error for incompatible method signatures.

Before this change, the derived class could arbitrarily change the signature, ignore the error, and move on. No longer needed: classes like abstract class and interface must comply with LSP.

0
source share

All Articles