In inheritance an object has a “is-a” relationship with other objects. An "is-a" relationship means that an object is or "can be seen as" another object. Thus, a derivative object can be seen as the object it was derived from. Here are some real world examples to give you a better idea of how you should interpret that:
• a car is a vehicle • a bike is a vehicle • a man is a human being • a woman is a human being
Example 1 illustrates this theory by implementing a (rather simplified) class that represents a human being.
Example 1
<?php
class HumanBeing { var $arms; var $legs; var $brains; /* * constructor * in PHP 5 this will be __construct() instead, although * this code will still work if there's no * __construct() available */
function HumanBeing($arms, $legs, $brains) { $this->arms = $arms; $this->legs = $legs; $this->brains = $brains; }
function walk($from, $to) { // code for letting human walk goes here }
function think($subject) { // code for letting human think goes here }
function waveArms() { // code for letting human wave its arms goes here } } ?> In OOP terminology, this would be called the baseclass for a human being. Let's pretend that it implements all the required properties and behavior a human being should have. See it as a universal human being. Of course we cannot implement a complete human being in code, but again, this is just by means of an example. We do know however, that man and woman are both human beings, thus, they can both derive from a human being object - they just need respective properties and behaviors added. This also means that if we want to implement a woman or man in code, we'd not have to implement all code necessary to indicate that this is a woman or man. We simply derive it from the human being object. This can save a lot of time and code. And that is also exactly what inheritance is about. To give you a better idea, Example 2 shows an implementation of a Woman class. Note that the superclass definition should always be available to the subclass when you want to extend from it.
Example 2
<?php /* * note: make sure the definition of the HumanBeing class is * included when implementing this * code * now that the definition for that class is available, we can extend from it */ class Woman extends HumanBeing { /* * at this point, our class has all properties and behaviour that have * been defined * in HumanBeing * let's add a property that is specific to a woman */
var $pregnant;
// constructor
function Woman($arms, $legs, $brains) { // make sure we initialize the superclass constructor parent::HumanBeing($arms, $legs, $brains);
// set pregnant to false by default $this->pregnant = false; }
// create modifier for pregnancy attribute function setPregnant($pregnantBool) { if ($pregnantBool != true && $pregnantBool != false) { echo "Error: invalid parameter for: "; echo "setPregnant(Boolean pregnantBool)"; } else { $this->pregnant = $pregnantBool; } }
// create accessor so see if woman is pregnant function isPregnant() { return $this->pregnant; } }
?>
The following example shows how to make a new instance of Woman which would also have the properties and behavior of HumanBeing. When you want to apply this snippet, you have to make sure that the definition of the Woman class is available to the script. Also note that in this case, the arguments passed to the constructor are most likely to be objects themselves, but for the sake of simplicity we have used strings. You can see that we invoke HumanBeing's waveArms(), which is possible because we extended Woman from HumanBeing.
<?php
$aWoman = new Woman("the womans arms", "the womans legs", "the womans brains"); $aWoman->waveArms(); $aWoman->setPregnant(true); if ($aWoman->isPregnant()) { echo "She's pregnant."; }
?>
Firstly, we have implemented all the relevant (note: this means relevant to how we want to apply one) properties and behavior for a human being. Then, we built upon that class by implementing a class that would represent a woman. In OOP-speak, the relationship between the HumanBeing class and the Woman class is as follows:
• Woman is a subclass of HumanBeing • HumanBeing is the superclass of Woman
We can also still say that Woman "is-a" HumanBeing. Note that it does not work both ways. A HumanBeing is absolutely not per definition a Woman, so we could say that the "is-a" concept is only recognized when we go from the bottom to the top of the hierarchy. A superclass cannot be seen as one of its subclasses, only the other way around. A subclass inherits all properties and behaviour from its superclass by extending from it. This is often called "programming by difference". All you basically do when subclassing, is adding properties and behaviour that make the subclass different from its superclass. When deriving a subclass from a superclass however, it should be very clear that the subclass is in fact a derivative from its superclass. This sounds obvious, but it is often mistaken. Do not try to replace composition by inheritance, they are two different things. When your subclass cannot be seen as being its superclass, do not apply inheritance.
Polymorphism One of inheritance's good friends is called polymorphism. First of all, I have to say that applying this technique is not likely going to have a huge impact when used in a weakly typed language such as PHP (i.e. the interpreter does not care about the types of our objects as they do in for example Java). Polymorphism basically means that a single class, method or variable name may present itself in many different forms. While this is interesting, PHP's nature makes sure that a lot of this happens automatically, since it has no concept of strong typing, thus all objects will be treated equally anyway. Conventionally however, it can make sense. Example 3 presents an example of polymorphism.
Example 3
<?php
class Base { // empty constructor function Base() {}
function displayStr() { echo "hello from base"; } }
class DerivedOne extends Base { // empty constructor function DerivedOne() {}
// overriding displayStr() in Base function displayStr() { echo "hello from derived class one"; } }
class DerivedTwo extends Base { // empty constructor function DerivedTwo() {}
// overriding displayStr() in Base function displayStr() { echo "hello from derived class two"; } }
$objects = array ( $baseInstance = new Base(), $derivedOneInstance = new DerivedOne(), $derivedTwoInstance = new DerivedTwo() );
foreach ($objects as $object) { $object->displayStr(). "<br />\n"; }
?>
What we have done in Example 3 is simple. We define a method displayStr() in a baseclass, and derive two classes from it, namely DerivedOne and DerivedTwo. We then define an array and put instances of the baseclass and its two subclasses into it, after which we loop over the array with the stored objects, and call their displayStr() method. This last part is what makes it interesting. We could say that DerivedOne and DerivedTwo both maintain an "is-a" relationship with Base, but as we can see, the displayStr() is what specializes them. In other words, these subclasses from the Base class behave differently while they are both "a Base". When you think a bit further about this concept, you might realize that this technique can be used to create generic code. Unfortunately, PHP has no concept of abstract classes (a mechanism that lets you programmatically force implementation rules when subclassing). If it did, we could quite simply force every subclass to implement showHTML(). Make sure to document properly what needs to be done when you want subclasses to override certain methods of their superclass, for yourself or for your team. It can save debugging time.
Conclusion
Object Oriented Programming is a powerful and often elegant approach to analyze, design, and implement a solution to a problem, but not something you master in days, weeks, or even years. It is certainly not the golden key to solve every problem that would be too good to be true. It might help you when designing average to large scale applications though.
|