Skip to content

Lecture Notes - Week 14

Readings

  • Chapters:
    • 26 - Introduction to Object Oriented Programming in PHP: pgs. 465 - 469
  • Anything else you can find on Object Oriented Programming (especially Inheritance & Overriding)

Screencasts - Week 14

Outline of Topics

  • Inheritance
  • Overriding Methods
  • Thoughts on Class Design ( Is a vs. Has a)
  • Demonstration

Lecture

Inheritance

In OOP, inheritance extends the behavior of one class (called the base or parent class) and reuses it as the basis of another class (called the sub or child class). Doing so allows for efficient reuse of code from a base class and is considered another central pillar of OOP. Another way to take advantage of inheritance is to design your base classes with the thought of more generalization and the sub-classes with more specificity.

This is best illustrated through an example. Let’s say we want to represent the idea of a pet:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
    class Pet
    {
        protected $name;

        // Getters / Setters
        public function getName()
        {
            return $this->name;
        }

        public function setName($name)
        {
            $this->name = $name;
        }

        // Do some exercise!
        public function exercise()
        {
            echo 'Exercising my pet ' . $this->name . '.<br />';
        }
    }

NOTE: Use protected (not private) to make parent properties available to your sub–classes

The Pet class will serve as our base class. If we want to create a more specific class with all the knowledge and methodology of a Pet, we need to create a sub-class. We do that by defining our sub–class and extending the base-class using the keyword extends:

1
2
3
4
5
6
<?php
    require_once('Pet.php');
    class Dog extends Pet
    {
        ...
    }

Since we are extending the Pet class, don’t forget to include it before declaring our sub-class. Now let’s add more specific functionality to our sub-class:

1
2
3
4
5
6
7
8
9
<?php
    require_once('Pet.php');
    class Dog extends Pet
    {
        public function bark()
        {
            echo $this->name . ' is barking.<br />';
        }
    }

Let's create another sub–class:

1
2
3
4
5
6
7
8
9
<?php
    require_once('Pet.php');
    class Cat extends Pet
    {
        public function meow()
        {
            echo 'My cat ' . $this->name . ' is meowing.<br />';
        }
    }

Here's how we might use these classes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
    require_once('Pet.php');
    require_once('Dog.php');
    require_once('Cat.php');

    // Create a pet, dog, and cat
    $my_pet = new Pet();
    $my_dog = new Dog();
    $my_cat = new Cat();

    // Set Pet's name and exercise
    $my_pet->setName("Gerald");
    $my_pet->exercise();

    echo '**********<br />';

    // Set Dog's name, exercise, and bark
    $my_dog->setName('Sparky');
    $my_dog->exercise();
    $my_dog->bark();

    echo '**********<br />';

    // Set Cat's name, exercise, and meow
    $my_cat->setName('Boo');
    $my_cat->exercise();
    $my_cat->meow();

You’ll notice that I include a reference to the Pet class even though Dog and Cat also include the Pet class. It is a best practice, as long as I am instantiating an object of a base class to include the base class, even though an instantiated sub-class inherits the base class as well. The reason is, I would minimize any breaking changes if the inheritance structure were to be redesigned. Remember to use require_once so you don’t get a fatal error when including a class that already exists.

And here is the output:

Overriding Methods

With inheritance, I can create more specific data and methods based on the details in my sub-class. However, I don’t like that my dog and cat are portrayed as exercising the same way. It would be handy to customize or override the different ways my dog and cat exercise.

Another central pillar of OOP is the ability to override the behavior of methods based on the specificity of the subclass. In fact, with the ability to override methods, we don’t have to keep track of which specific method to use. We can rely on each subclass taking care of its unique details for how something is done. It is done automatically for us based on the subclass type. This behavior is called polymorphism (meaning many forms), another main pillar of OOP.

We override the behavior of a base class’s method by redefining it in the sub-class. The rule is: the method in the subclass must have the exact same signature as the method in the base class.

Here is the Dog class with excercise() overridden:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
    require_once('Pet.php');

    class Dog extends Pet
    {
        public function bark()
        {
            echo $this->name . ' is barking.<br />';
        }

        // Do some dog exercise!
        public function exercise()
        {
            echo 'Walking my dog ' . $this->name . '.<br />';
        }
    }

Here is the Cat class with excercise() overridden:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
    require_once('Pet.php');
    class Cat extends Pet
    {
        public function meow()
        {
            echo 'My cat ' . $this->name . ' is meowing.<br />';
        }

        // Do some cat exercise!
        public function exercise()
        {
            echo 'My cat ' . $this->name . ' is chasing mice!<br />';
        }
    }

A powerful feature of OOP is we don’t have to make any changes to code that uses the Pet, Dog, and Cat class since we call the methods the same way. Just rerun it and notice the change in the output:

Thoughts on Class Design

Now that you're armed with the knowledge of basic class creation, inheritance, and overriding, you have some good tools available to you for how you design your classes. Let's take a simple example of modeling a house in software. For example, let's say we have a house with three rooms in it: a bedroom, bathroom, and kitchen. And let's just focus on one of these rooms: the bathroom. A bathroom is a room, and a bathroom has things like a sink and toilet in it.

The Is a vs. Has a Test

This is known as the Is a vs. Has a test. Specifically, it tests the relationship between two things. When designing classes, you ask the question: Is a bathroom a room. You also ask the question are all rooms bathrooms. If the Has a question passes, (usually) only one of these questions will be true. This will give the directionality of the inheritance relationship. Which means Room will be the base or parent class of Bathroom. Let's ask the Is a question again of the relationship between a bathroom and a sink: Is a bathroom a sink? No. Is a sink a bathroom? No again. Therefore the relationship between a bathroom and a sink fails the Is a test and is not a candidate for inheritance. Next let's move on to the Has a test. So, then we ask the question: Does a sink have a bathroom? No. Does a bathroom have a sink? Yes! In the same way as the Is a test, we ask the Has a test both ways to establish directionality. Since we pass the Has a test: A bathroom has a sink, we can make a Sink object a property of the Bathroom class. This is known as Composition.

There is a lot more to proper class design, however the Is a and Has a test is a foundational principle that will give you a lot of mileage as you're thinking about how to design your classes

Demonstration of Inheritance and Overriding