Class Inheritance

Passing Down Code Wisdom through Generations

Who would have guessed that PHP supports inheritance? Everyone using PHP since Object Oriented Programming became a thing, that’s who. If you’re not familiar with inheritance in programming, it’s just mimicking real world concepts, primarily ancestral inheritance. You inherit traits or characteristics from your parents, your parents from their parents and so on. You and I share the same traits as all human beings, so our parent class can be Human. In that Human class we can list methods like walking and speaking. Even though we speak different languages, the mechanism is the same. We share the capability to speak and use the same organs to accomplish the task.

In Object Oriented Programming, you can inherit both properties and methods from other classes. The class that inherits is called the child class; it inherits from the parent class. Child classes are also called subclasses and parent classes are referred to as superclasses.

We’re going to be modifying our GermanShepherd class from the previous article.

https://www.dinocajic.com/php-getters-and-setters/

We’ll move quite a few properties outside of the GermanShepherd class and into a more generic Dog class. We can also modify the Car class, even though it’s an abstract enough concept, to inherit from a more generic Vehicle class. We’ll cover that in the next article.

Let’s start with the GermanShepherd class. Every GermanShepherd is a Dog and there are different dog breeds like Poodles and German Shepherds.

<?php
// Inheritance

class GermanShepherd
{
const HAS_HEART = true;
const HAS_TAIL = true;

private $eye_color;
private $dob;
private $does_shed = true;
private $kingdom = "Animalia";
private $phylum = "Chordata";
private $class = "Mammalia";
private $order = "Carnivara";
private $family = "Canidae";
private $genus = "Canis";
private $species = "Canis Lupus";
private $subspecies = "Canis Lupus Familiaris";
private $breed = "German Shepherd Dog";
private $fur_color;

public function __construct(string $eye_color,
string $dob,
string $fur_color)
{
$this->eye_color = $eye_color;
$this->dob = $dob;
$this->fur_color = $fur_color;
    }

/**
     * @return string
     */
public function getEyeColor(): string
{
return $this->eye_color;
    }

/**
     * @param string $eye_color
     */
public function setEyeColor(string $eye_color): void
{
$this->eye_color = $eye_color;
    }

/**
     * @return string
     */
public function getDob(): string
{
return $this->dob;
    }

/**
     * @param string $dob
     */
public function setDob(string $dob): void
{
$this->dob = $dob;
    }

/**
     * @return bool
     */
public function isDoesShed(): bool
{
return $this->does_shed;
    }

/**
     * @param bool $does_shed
     */
public function setDoesShed(bool $does_shed): void
{
$this->does_shed = $does_shed;
    }

/**
     * @return string
     */
public function getFurColor(): string
{
return $this->fur_color;
    }

/**
     * @param string $fur_color
     */
public function setFurColor(string $fur_color): void
{
$this->fur_color = $fur_color;
    }

public function walk()
{
echo "I'm walking";
    }

public function bark()
{
echo "I'm barking";
    }

public function sleep(int $energy_level = 100)
{
if ($energy_level < 40) {
echo "I'm sleeping";
        } else {
echo "I don't want to sleep";
        }
    }

public function get_scientific_classification(): array
{
return [
"kingdom" => $this->kingdom,
"phylum" => $this->phylum,
"class" => $this->class,
            "order" => $this->order,
            "family" => $this->family,
            "genus" => $this->genus,
            "species" => $this->species,
            "subspecies" => $this->subspecies,
            "breed" => $this->breed
        ];
    }

public function __destruct()
{
//        var_dump(
//            [
//                "eye_color" => $this->eye_color,
//                "dob" => $this->dob,
//                "does_shed" => $this->does_shed = true,
//                "kingdom" => $this->kingdom = "Animalia",
//                "phylum" => $this->phylum = "Chordata",
//                "class" => $this->class = "Mammalia",
//                "order" => $this->order = "Carnivara",
//                "family" => $this->family = "Canidae",
//                "genus" => $this->genus = "Canis",
//                "species" => $this->species = "Canis Lupus",
//                "subspecies" => $this->subspecies = "Canis Lupus Familiaris",
//                "breed" => $this->breed = "German Shepherd Dog",
//                "fur_color" => $this->fur_color,
//            ]
//        );
    }
}

Starting with the constants, each Dog has a heart and a tail, so we can move that to our new Dog class.

<?php

class Dog{

const HAS_HEART = true;
const HAS_TAIL = true;
}
Next are the properties. Each Dog has a specific eye color, date of birth, etc. We can move all of the properties to our Dog class. The only thing that we’ll have to change is the breed. Once breed is part of the Dog class, it doesn’t make sense to leave it initialized as German Shepherd since we can use our Dog class to make other breeds. We don’t want a German Shepherd Poodle.
<?php
// Class Inheritance

class Dog {
    const HAS_HEART = true;
    const HAS_TAIL = true;

    protected $eye_color;
    protected $dob;
    protected $does_shed = true;
    protected $kingdom = "Animalia";
    protected $phylum = "Chordata";
    protected $class = "Mammalia";
    protected $order = "Carnivara";
    protected $family = "Canidae";
    protected $genus = "Canis";
    protected $species = "Canis Lupus";
    protected $subspecies = "Canis Lupus Familiaris";
    protected $breed;
    protected $fur_color;
  
}
You might have noticed that we switched the private property modifiers to protected. We touched on visibility modifiers in the previous article, including the protected visibility modifier.

If we moved the properties with the private visibility modifier to the Dog class, our GermanShepherd class would not have access to those properties when inheriting. To make sure that our GermanShepherd class inherits those properties, we have to make the modification from private to protected.

We’ve talked about inheritance as a concept so far, but how can the GermanShepherd class actually inherit properties from the Dog class. With the help of the extends keyword.

class ChildClass extends ParentClass

You can only extend (inherit) one class. Our Dog class can also inherit from another class, like Animal.

<?php
// Class Inheritance

class Dog {
    const HAS_HEART = true;
    const HAS_TAIL = true;

    protected $eye_color;
    protected $dob;
    protected $does_shed = true;
    protected $kingdom = "Animalia";
    protected $phylum = "Chordata";
    protected $class = "Mammalia";
    protected $order = "Carnivara";
    protected $family = "Canidae";
    protected $genus = "Canis";
    protected $species = "Canis Lupus";
    protected $subspecies = "Canis Lupus Familiaris";
    protected $breed;
    protected $fur_color;
}

class GermanShepherd extends Dog
{

    public function __construct(string $eye_color,
                                string $dob,
                                string $fur_color)
    {
        $this->eye_color = $eye_color;
        $this->dob = $dob;
        $this->fur_color = $fur_color;
    }
  
    //...
}
To test this, let’s create a new GermanShepherd object and echo out the eye color after instantiation.
<?php

$gs_dog = new GermanShepherd("Green", "Oct 10, 2015", "Brown");
echo "Eye Color: " . $gs_dog->getEyeColor();

The result that you should receive is Green. Even though the eye_color property does not exist within the child class, it does exist in the parent class and is being inherited. The concept can be confusing for beginners, especially when you see that the getEyeColor() method is returning $this->eye_color. The keyword $this is referencing the object it’s in, i.e. GermanShepherd, and the eye_color property does not exist there any more. And yet, the eye color is returned properly. To visualize it better, think of the properties as being copied from the parent class to the child class; however, when you’re looking through the code and can’t find the property, you’ll start making your way up the inheritance tree. You’ll find the eye_color property in the Dog parent class.

As mentioned earlier, we can move properties and methods to our parent class. Taking a look at our GermanShepherd class, none of the methods are unique to GermanShepherds, so we can move them all to our Dog class.

<?php
// Class Inheritance

class Dog {
    const HAS_HEART = true;
    const HAS_TAIL = true;

    protected $eye_color;
    protected $dob;
    protected $does_shed = true;
    protected $kingdom = "Animalia";
    protected $phylum = "Chordata";
    protected $class = "Mammalia";
    protected $order = "Carnivara";
    protected $family = "Canidae";
    protected $genus = "Canis";
    protected $species = "Canis Lupus";
    protected $subspecies = "Canis Lupus Familiaris";
    protected $breed;
    protected $fur_color;

    /**
     * @return string
     */
    public function getEyeColor(): string
    {
        return $this->eye_color;
    }

    /**
     * @param string $eye_color
     */
    public function setEyeColor(string $eye_color): void
    {
        $this->eye_color = $eye_color;
    }

    /**
     * @return string
     */
    public function getDob(): string
    {
        return $this->dob;
    }

    /**
     * @param string $dob
     */
    public function setDob(string $dob): void
    {
        $this->dob = $dob;
    }

    /**
     * @return bool
     */
    public function isDoesShed(): bool
    {
        return $this->does_shed;
    }

    /**
     * @param bool $does_shed
     */
    public function setDoesShed(bool $does_shed): void
    {
        $this->does_shed = $does_shed;
    }

    /**
     * @return string
     */
    public function getFurColor(): string
    {
        return $this->fur_color;
    }

    /**
     * @param string $fur_color
     */
    public function setFurColor(string $fur_color): void
    {
        $this->fur_color = $fur_color;
    }

    public function get_scientific_classification(): array
    {
        return [
            "kingdom" => $this->kingdom,
            "phylum" => $this->phylum,
            "class" => $this->class,
            "order" => $this->order,
            "family" => $this->family,
            "genus" => $this->genus,
            "species" => $this->species,
            "subspecies" => $this->subspecies,
            "breed" => $this->breed
        ];
    }

    public function walk()
    {
        echo "I'm walking";
    }

    public function bark()
    {
        echo "I'm barking";
    }

    public function sleep(int $energy_level = 100)
    {
        if ($energy_level < 40) {
            echo "I'm sleeping";
        } else {
            echo "I don't want to sleep";
        }
    }
}

class GermanShepherd extends Dog
{

    public function __construct(string $eye_color,
                                string $dob,
                                string $fur_color)
    {
        $this->eye_color = $eye_color;
        $this->dob = $dob;
        $this->fur_color = $fur_color;
    }
}

Looks pretty clean. You may be tempted to change all of your public methods to protected methods. Your child class will have access to the methods, however, once the object is instantiated, no methods will be visible.

Let’s change the getEyeColor() visibility modifier from public to protected and run our code again. You’ll see a Fatal Error displayed.

 

You may be asking yourself what the point of even creating a GermanShepherd object is if we’re just moving everything to the Dog class. Aside from it being the right thing to do, you can override your methods inside of the GermanShepherd class and make them GermanShepherd specific. For example, there is a default bark() method that echos “I’m barking.” We can override that method inside of our GermanShepherd class so that the GermanShepherd can say “Loud Barking.”

How do you override a method? You create a method inside of the child class (GermanShepherd) and name it the method that you’re trying to override. You do not delete the bark method from the Dog class.

<?php
// Class Inheritance

class Dog {
    //...

    protected $eye_color;
    
    //...

    public function bark()
    {
        echo "I'm barking";
    }

    //...
}

class GermanShepherd extends Dog
{

    public function __construct(string $eye_color,
                                string $dob,
                                string $fur_color)
    {
        $this->eye_color = $eye_color;
        $this->dob = $dob;
        $this->fur_color = $fur_color;
    }

    public function bark() {
        echo "Loud Barking";
    }

    //...
}

$gs_dog = new GermanShepherd("Green", "Oct 10, 2015", "Brown");
echo "Eye Color: " . $gs_dog->getEyeColor() . "<br>";
echo $gs_dog->bark() . "<br>";

Calling the bark() method outputs Loud Barking since the method was successfully overridden. When we call the bark() method, PHP will go into the GermanShepherd object and start looking for the bark() method. If it finds it, great. If it doesn’t, it starts looking up the inheritance tree.

There are still a couple of more concepts to learn when it comes to inheritance, but we’ll cover that in the next article.

Continue your learning with these articles

PHP Getters and Setters

SAFEGUARDING AND SCULPTING WITH GETTERS AND SETTERS

PHP – P52: GETTERS AND SETTERS

If we wanted to access those properties or modify them in their current state, we wouldn’t be able to. That’s where getters and setters, or accessors and mutators, come into play.

Class Inheritance

Passing Down Code Wisdom through Generations

PHP – P53: CLASS INHERITANCE

Who would have guessed that PHP supports inheritance? Everyone using PHP since Object Oriented Programming became a thing, that’s who.

Inheritance Chain

TRACING THE LINEAGE OF FUNCTIONALITY IN INHERITANCE CHAINS

PHP – P54: INHERITANCE CHAIN

In the last article I mentioned briefly that you can’t extend multiple classes at once. But the parent class can itself be a child class and extend a class of its own.

Leave a Reply