Inheritance is a term for reusing code by a mechanism of passing down information and behavior from a parent class to a child or subclass. It’s pretty easy to understand really. Just like a child can inherit various mannerisms and behaviors from his or her biological parents, in software this same concept holds true. By leveraging the power of inheritance and creating child classes that extend their parent, we can make subclasses with superpowers that have everything their parent has and more. Let’s take a look at how inheritance works in PHP.
The extends
keyword
Any time you see the extends keyword in use, you know that inheritance is being used. Following along the biological example of inheritance, we can see how a Son might inherit from a Father.
class Father
{
public function getGender()
{
return 'Male';
}
}
class Son extends Father
{
}
echo (new Son)->getGender();
// Male
As we can see in the example, when we new up, or instantiate a Son
object, we are able to make use of the getGender()
method. If you look in the Son
class however, it is a blank slate with nothing in there. How are we able to make use of that method? We can make use of the getGender()
method because of Inheritance. Specifically, the Son
class inherits from the Father
class. This is exactly why we use inheritance. We use it for when we want to inherit behavior from a parent class. Of course since people love jargon so much, the parent class could also be referred to as the base class or super class. The child class goes by things such as the derived class, the sub class, or the heir class. They all mean the same thing.
Frameworks Use Inheritance
The reason why Frameworks in programming are so popular is that we get to make use of well-tested software without having to reinvent the wheel by use of inheritance. For example, in the Laravel PHP Framework, in order to make use of the popular Eloquent Active Record implementation, our class needs to extend the Model. When you extend the model like so:
class Link extends Model {}
$link = new Link;
You now get access to all of the methods found at this link, and it’s a lot of them! So by writing about two lines of code, you get to access hundreds of extremely helpful methods. That sounds like a good deal, right? That is exactly what inheritance is for.
Implementing Shared Behavior
In addition to code reuse, inheritance is good for the ability to implement shared behavior. Consider a Vehicle
class. All vehicles will have wheels, and we should be able to fetch the number of wheels for any given vehicle. So let’s add a getWheels()
method to our parent class.
<?php
class Vehicle {
public function getWheels()
{
}
}
class Car extends Vehicle {
}
class Unicycle extends Vehicle {
}
class Motorcycle extends Vehicle {
}
class Segway extends Vehicle {
}
Hmm… Notice a problem there? We want to make use of inheritance to make fetching the number of wheels from any of our Vehicles easier. The problem is, the algorithm to fetch the number of wheels for a Car
versus a Unicycle
is different. So it would seem that we can’t place just one method in the parent class and expect all the subclasses to be able to use it successfully in this case. How can we overcome this?
Shared Behavior Design
By looking at our collection of vehicles, we can see that a Motorcycle
and a Segway
could probably make use of the same algorithm. This is to say, both of them have two wheels. So if we have a case where the same algorithm can solve a problem for more than one type of sub-class, then we can put that common behavior in the parent class. Let’s take care of that now.
class Vehicle {
public function getWheels()
{
return 'Two Wheels';
}
}
class Car extends Vehicle {
}
class Unicycle extends Vehicle {
}
class Motorcycle extends Vehicle {
}
class Segway extends Vehicle {
}
echo (new Motorcycle)->getWheels();
// Two Wheels
echo (new Segway)->getWheels();
// Two Wheels
Method Overriding
The prior example is a good solution to sharing behavior, but it also introduces a problem. Our Car
class currently extends the Vehicle
class. The Vehicle
class has a dedicated method for fetching the number of wheels of our Vehicle. Let’s try out the method on an instance of the Car
class.
echo (new Car)->getWheels();
// Two Wheels
Whoops. It looks like our software has a bug. We called the getWheels()
method on our Car
class and it returned a value of Two Wheels. Cars don’t have Two Wheels, they have Four. In this case, we need to provide the Car
class with it’s own implementation of the getWheels()
method, and we can do this by replacing or overriding the method of the parent class. We’ll just make one small change to our Car
class to get it working correctly.
class Vehicle {
public function getWheels()
{
return 'Two Wheels';
}
}
class Car extends Vehicle {
public function getWheels()
{
return 'Four Wheels';
}
}
echo (new Car)->getWheels();
// Four Wheels
Now, even though the Car
class inherits from the Vehicle
class, it is able to return the correct number of wheels for a Car
since it has it’s own implementation of the getWheels()
method. Any time you need a unique behavior for a sub class, you can easily override methods of the parent class.
What If All Sub Classes Are Unique?
Let’s imagine that we only have a Car, Motorcycle, and Unicycle. We still have the Vehicle class that we want to extend from. Is there anything to be gained from trying to implement a shared behavior in the parent class at this point? There is no shared behavior anymore, so probably not. We no longer have a shared behavior, but it would still be nice to be able to fetch the number of wheels from our three different types of Vehicles. There are two reasons why a Vehicle parent class might still be useful.
- 1. Will there be any attributes that could be shared across every Vehicle? If so, put this in the parent class to prevent having to write the same thing multiple times in the subclasses.
- 2. Do you still want the ability to implement a specific behavior on all subclasses, even if each implementation is different? If so, you can force this by way of a contract in an abstract class with the template method design pattern.
Let’s add these two ideas to our abstract parent Vehicle class.
abstract class Vehicle
{
protected $color;
public function __construct($color = 'Blue')
{
$this->color = $color;
}
public function getColor()
{
return $this->color;
}
abstract protected function getWheels();
}
class Car extends Vehicle {
public function getWheels()
{
return 'Four Wheels';
}
}
What this code does is implement the ability to both set a color and retrieve the color of any sub-class that extends from the Vehicle. This way, you only need to write the code in the constructor and set up a getter once, in the parent class. You will not need to write this over and over in the subclasses. We also have implemented an abstract protected method which forces subclasses to declare their own implementation of a getWheels()
method. This is kind of similar to how an interface works. If we try to make a class that extends from Vehicle and we don’t include a getWheels() method, an exception will be thrown. Let’s see.
abstract class Vehicle
{
protected $color;
public function __construct($color = 'Blue')
{
$this->color = $color;
}
public function getColor()
{
return $this->color;
}
abstract protected function getWheels();
}
class Unicycle extends Vehicle {
}
echo (new Unicycle)->getWheels();
// Fatal error: Class Unicycle contains 1 abstract method and must therefore
// be declared abstract or implement the remaining methods (Vehicle::getWheels)
If we behave ourselves, however, and follow the contract, all is well.
abstract class Vehicle
{
protected $color;
public function __construct($color = 'Blue')
{
$this->color = $color;
}
public function getColor()
{
return $this->color;
}
abstract protected function getWheels();
}
class Unicycle extends Vehicle {
public function getWheels()
{
return 'One Wheel';
}
}
echo (new Unicycle)->getWheels();
// One Wheel
echo (new Unicycle)->getColor();
// Blue
Why Use Inheritance Summary
In this tutorial, we had a good look at one of the bread and butter concepts of object-oriented programming, and that is making use of inheritance. Being the lazy lot that we are, developers love to make good use of anything that can make our lives easier and prevent us from having to re-invent the wheel. Inheritance helps us with just that task. You may also be interested in the new ES6 Inheritance features to learn about.