Being a fundamental pillar of Object Oriented Programming, Inheritance is by far the most overrated method for reusing implementations. This happens because for a logical reason: it’s fairly easy to model real world (or virtual) objects which are interrelated by an “ISA” relationship. Add to this the flexibility that most programming languages provide when it comes to creating hierarchies of classes, and you’ll begin to understand why this occurs.
Unfortunately, the easy-going nature of Inheritance comes with a hidden cost that many times we’re reluctant to accept and pay (like bills and taxes). In many cases, the lack of proper planning and analysis leads to encapsulating common functionality in the wrong abstractions (not to mention the fact that Composition is often seen as something that must be avoided by all means, either due to ignorance or plain laziness).
While this may seem a minor issue that has little or no influence in the development of object-oriented applications, the truth is that dealing with a badly-designed hierarchy of objects can make you pull your hair out. Want a quick, succinct example of this? If you start spawning a bunch of subclasses whose behavior is wildly different from the one present in their base parent (or from the interface that they might implement), sooner or later you’ll end up breaking the functionality of the client code, even in the most forgiving cases.
However, not all is bad with Inheritance. When used properly it can be a great ally. The question that comes to mind is: how can you keep away from building derivatives that behave totally different from the chosen abstraction(s)? Here’s exactly where the Liskov Substitution Principle (LSP) comes into play. Its academic definition states the following:
“What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.”
“Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.”
Certainly, that’s way easier to undertand! Even though LSP (http://en.wikipedia.org/wiki/Liskov_substitution_principle) is per se fairly technical - you’ll have to get familiar with concepts like pre/post conditions, invariance, co variance and contra variance (for more information on these topics, be sure to check Giuseppe Castagna’s insightful paper here [http://c2.com/cgi/wiki?ContraVsCoVariance]) - its formulation is aimed at encouraging the creation of programs where subclasses of a certain type must have at least the same functionality as their parent. And if, for some reason, it’s necessary to override one or more methods implemented by the parent in question (which in the real world happens quite frequently), this must be clearly specified and documented.
To sump up, LSP is part of the SOLID principles (http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29), and as such, deserves an in-depth look. In keeping with this idea, in this two-part tutorial I’ll be demonstrating (with a real-world example other than the classic rectangle/square dilemma that the article’s title stands for) why you should care about it when developing your own OOP PHP applications, and how it can help you be a better, more conscious developer.