Published on May 28, 2011 by Pim Elshoff
Programming #Inheritance #OOP #Architecure #PHP
A very powerful and dangerous tool in the OOP toolbox is inheritance. Without it, OOP is utterly pointless and totally useless. Inheritance is the way to re-use functionality without re-implementing it. Inheritance will even feed your kittens! Read on for all the magic.
Inheritance is the mechanism of specializing a class into a more concrete form. For example, a student may be seen as a special sort of a person. A student has all the properties and methods that a person has and more. In terms of programming it would be a waste to have to implement all that code twice, so in PHP we can use the keyword extends (other languages use keywords such as inherits, or operators such as :) to tell PHP that we are specializing from a given class:
class Student extends Person
...
// Student inherits __construct()
$pim = new Student(“Pim”);
// My name is Pim
$pim->echoName();
A class that extends another class is called a subclass or child. The class the child extends from is called a superclass or parent. The tree you could draw up to show all inheritance relationships is called the class hierarchy or inheritance tree. All classes that precede a child in the class hierarchy are called ancestors. All classes that come after a parent in the class hierarchy are called descendants.
A real world example of inheritance is biological taxonomy. For example, every person could be an object of class ‘Homo Sapien’, which in turns could be a subclass of ‘Primate’ and a descendant of ‘Mammal’.
In rereading my first article I noticed I already had given the following definition of the protected keyword. My apologies for the premature, eh, definition. Now that we have talked about class hierarchy, we can understand what it means.
Protected properties and methods can be called from inside the object and up the class hierarchy
Private meant that only objects that instantiate the class directly can modify the property. Public meant that the property is generally accessible. Protected means that objects that instantiate the class, either directly or indirectly, can modify the property. Example:
class Person
{
protected $name;
...
}
class Student extends Person
{
protected $studentId;
public function echoNameAndNumber()
{
echo “My name is $this->name and my number is $this->studentId”;
}
// Student inherits __construct()
$pim = new Student(“Pim”);
$pim->setStudentId(123);
// My name is Pim;
$pim->echoName();
// My name is Pim and my number is 123
$pim->echoNameAndNumber();
// This will cause an error, because name is protected
echo $pim->name;
In this example, object $pim of class Student is allowed to access the property name, which was defined in Person, but the global scope is not.
When should you use protected and when private? I don’t think anyone has a final answer, but here are two perspectives:
Personally, I think number 2 is the better option. In my opinion number one is a wonderfully pragmatic approach, but pragmatism is no replacement for decent design. I will probably write more on this later. Or sooner.
In PHP, you are allowed to overwrite methods and properties that have been defined in a superclass. This is a wonderful trick on the best of days and a dreadful nightmare on the worst. It allows you to program special cases for special subclasses, but it also allows you to completely change the intentions of the person who wrote the superclass - even if that person was you.
If anything, I want to leave you with the following:
Don’t break the contract. Never ever break the contract.
This means: if the parent’s method has parameters and a return type, then the child’s method better accept the same parameters and return the same type. You can extend the set of parameters, but not change the existing ones. You can return a different value, but not a different type.
PHP strongly differs from various other languages such as Java in how it identifies methods. PHP does not identify them by their entire signature (name and parameters), but by their name only. This means that, when you are overwriting a method, PHP cannot tell if you meant to call the function as defined in the parent, or if you wanted the function as defined in the child. PHP always calls the child and it is up to you to pass that call along to the parent.
I know you don’t really want to, but a man (or woman) has to do what a man (or woman) has to do. So if you need to call your parent class, you can do so as follows:
public function someEarlierDefinedMethod($parameter)
{
parent::someEarlierDefinedMethod($parameter);
}
public function __construct($otherParameter)
{
parent::__construct($otherParameter);
}
Remember how the :: operator is used to tell PHP how to resolve the scope? The parent keyword tells PHP to bubble that method call up exactly one level. If you want, you can name the ancestor-to-call directly:
public function someEarlierDefinedMethod($parameter)
{
ParentClassName::someEarlierDefinedMethod($parameter);
}
public function __construct($otherParameter)
{
GrandParentClassName::__construct($otherParameter);
}
Bonus points for readers who can tell me why statically calling the parent class is no problem. Hint: I repeat, the :: operator is known as the ‘scope resolution operator’ and PHP has (had) it’s fair share of issues with late static binding.
Sometimes parents are like that. ‘This is how it is and that’s final!’ I guess the inventors of OOP (or at least PHP) have had this experience, because they made a keyword of it :)
The final keyword tells PHP that there can be no further extending on the method or class. For example, the following code will crash:
final class Person {…}
class Student extends Person {…}
If you are absolutely convinced that your code should not be extended, you can use the final keyword to make sure it won’t.
At Crowd Surfing, we have a few cases in which we have made a few methods final, to ensure that extended functionality for a given component would be created via plug-in functionality and not directly. This guarantees that no programmer overwrites certain methods and thereby changes the control flow of the component.
Alright, today we looked into inheritance, one of the key aspects of object oriented programming. The next article will cover polymorphism, which is sort of like inheritance on acid. The key aspects of this article include:
Sorry I never got around to that feeding kittens part. Maybe next article.
This article is part of the Object Oriented Programming series.
Be the first to comment!
No trackbacks yet