- Modular Programming with PHP 7
- Branko Ajzele
- 587字
- 2021-07-14 10:06:00
Liskov substitution principle
The Liskov substitution principle talks about inheritance. It specifies how we should design our classes so that client dependencies can be replaced by subclasses without the client seeing the difference, as per the definition found on Wikipedia:
"objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program"
While there might be some specific functionality added to the subclass, it has to conform to the same behavior as its base class. Otherwise the Liskov principle is violated.
When it comes to PHP and sub-classing, we have to look beyond simple concrete classes and differentiate: concrete class, abstract class, and interface. Each of the three can be put in the context of a base class, while everything extending or implementing it can be looked at as a derived class.
The following is an example of LSP violation, where the derived class does not have an implementation for all methods:
interface User { public function getEmail(); public function getName(); public function getAge(); } class Employee implements User { public function getEmail() { // Implementation... } public function getAge() { // Implementation... } }
Here we see an employee
class which does not implement the getName
method enforced by the interface. We could have easily used an abstract class instead of the interface and abstract method type for the getName
method, the effect would have been the same. Luckily, the PHP would throw an error in this case, warning us that we haven't really implemented the interface fully.
The following is an example of Liskov principle violation, where different derived classes return things of different types:
class UsersCollection implements \Iterator { // Implementation... } interface UserList { public function getUsers(); } class Emloyees implements UserList { public function getUsers() { $users = new UsersCollection(); //... return $users; } } class Directors implements UserList { public function getUsers() { $users = array(); //... return $users; } }
Here we see a simple example of an edge case. Calling getUsers
on both derived classes will return a result we can loop through. However, PHP developers tend to use the count
method often on array structures, and using it on Employees
instances the getUsers
result will not work. This is because the Employees
class returns UsersCollection
which implements Iterator
, not the actual array structure. Since UsersCollection
does not implement Countable
, we cannot use count
on it, which leads to potential bugs down the line.
We can further spot LSP violations in cases where the derived class behaves less permissively with regard to method arguments. These can usually be spotted by use of the instance of type
operator, as shown in the following example:
interface LoggerProcessor { public function log(LoggerInterface $logger); } class XmlLogger implements LoggerInterface { // Implementation... } class JsonLogger implements LoggerInterface { // Implementation... } class FileLogger implements LoggerInterface { // Implementation... } class Processor implements LoggerProcessor { public function log(LoggerInterface $logger) { if ($logger instanceof XmlLogger) { throw new \Exception('This processor does not work with XmlLogger'); } else { // Implementation... } } }
Here, the derived class Processor
puts restrictions on method arguments, while it should accept everything conforming to the LoggerInterface
. By being less permissive, it alters the behavior implied by the base class, in this case LoggerInterface
.
The outlined examples are merely a fragment of what constitutes a violation of LSP. To satisfy the principle, we need to make sure that derived classes do not, in any way, alter the behavior imposed by the base class.
- Docker and Kubernetes for Java Developers
- Python從菜鳥到高手(第2版)
- Nginx Essentials
- 用Flutter極速構建原生應用
- Magento 1.8 Development Cookbook
- QGIS By Example
- Building RESTful Python Web Services
- Mastering C++ Multithreading
- R數據科學實戰:工具詳解與案例分析
- Learning Material Design
- SQL Server 2008 R2數據庫技術及應用(第3版)
- Python 3 數據分析與機器學習實戰
- 創意UI Photoshop玩轉移動UI設計
- 軟件測試技術
- Monitoring Docker