Classes and OOP (Part 3)

1.0 Previous Tutorial

This is the third tutorial in a series of tutorials on classes and OOP.

First Tutorial
Second Tutorial

In the previous tutorial we learned about the difference between a static context class and an object context class and that a static class is considered as bad practice.

We also learned about the 14 different magic methods that PHP provides you with to aid you in the creation and extension of your system.

1.1 Introduction to tutorial

This tutorial assumes that the reader has read and understood the previous two tutorials (especially the first) as we would go on with our class we are writing and add to it in this tutorial. It is time to dig deeper into the world of classes and OOP.

As a reminder, we left off with the following class.

class fruit
{

    private $amount = 2;

    public function eat()
    {
        // Chew
    }

    public function amount($number)
    {
        if($number < 11)
        {
            $this->amount = $number;
        }
    }

}

2.0 Extending Classes

In the real world we have a vehicle we know as a Hummer H2. The car isn't a very lengthy SUV... unless you extend it and turn it into a limousine. The extra part of the Hummer H2 that extends the original Hummer H2 utilizes the same stuff the original Hummer provides and on top of that, adds it's own additions such as a T.V., fridge, recliner, more space, etc.

Same with classes (well, the programming world IS in the real world) we could extend one class with another adding functionality to the first class with a second class.

Now, you may wonder why write another class and extend the first class to add features to the first class instead of just editing the first class and adding those features that way. Good thought, let's dwell on it a bit and figure out why people might do such a thing.

When you have a complicated system where certain different functions of the system utilizes a portion of the same code (but does a different function/performs a different role), this comes in very handy. Really makes the system very easy to build on, and increase.

In our case, we have a class named fruit. A fruit is a very broad terms. An apple is a fruit, and so is an orange. The are different kind of products, but they share one common denominator... they are both fruits.

Here where this comes into play, we create a class 'fruit' with all the common functions of a 'fruit' but leave the specific functions of each different fruit to it's own class to define.

You would eat and apple a bit differently then you would eat an orange, right? You would wash the apple and devour it, whereas you don't need to wash the orange, though you would need to either peel it or cut it to slices so you can actually get to the orange. The steps needed to eat those two fruits are different, and a generic class 'fruit' is not enough to define the function needed to eat both fruits... otherwise, it will be very messy.

Below is a class we could right for an apple.

class apple extends fruit
{

    protected function prepare()
    {
        echo "Washing the apple.<br />";
    }

}

I want to stop here for a little and explain that code a little bit, as there are some new information you need to know about that class.

You would notice the added extends fruit at the end of 'class apple' (the beginning of any class). This is how we tell the script that this class is extending on the other class (named fruit). This means that the class 'fruit' (the one being extended) becomes a parent (parent class) and the class which is extending (class apple in this case) is the child (the child class).

So let's start a family!! 😁

What I noticed is that there is no particular order required in which you define the classes, you can define the child class before the parent class or vice versa and it'll work just fine, they just need to be defined and accessible to the script at run-time.

Now that we have that second class with it's function, let's edit the parent class (fruit) function eat. So instead of what we have now, it would be.

public function eat()
{
    $this->prepare();
}

And now to use the class, you would only need to initiate the child class and then all of those functions are available to you through the child class (including the parent's functions).

$product = new apple();

$product->eat();

What you are doing with that code right there is initiating the child class and setting the object to a variable '$product' and then (3rd line) you are calling on a function found in the parent class (you didn't initiate yourself like you did with the child class) and then the function found in the parent class is calling on a function inside the child class. (I hope that made sense).

The outcome of that code would be:

Washing the apple.

I want to stop here as well and explain a few things that you may have noticed... or just voice your observations 🙂

We are asking the parent class, function eat to use a function described in a child class and not in the parent class. You can do that because you are extending that parent class with the child class, so all of parent's functions become available to the child and all the child's functions become available to the parent.

You would also notice that $this is used in the parent class to access the function located in the child class. (Not $that 🤣 ).

Another thing you might have noticed is that the function 'prepare' in the child class is marked as protected instead of public. What that does is allow the parent class to use the function (whereas 'private' would block the parent from using it), but it blocks the function from being accessed outside of the function. So if we do something like the following:

$product->prepare();

You would get a fatal error.

Fatal error: Call to protected method apple::prepare() from context '' in C:\xampp\htdocs\www\classesAndOop\classes_and_oop.php on line 34

You might wonder, why do that? Well, the answer is pretty simple actually... there is an order, or a step by step process in which you do things, and if everyone is able to call on those functions and mess with the order, you will have a huge problem. For instance, try swallowing the apple, then wash it and then chew it. That is impossible.

So what we do here is have the parent class, function eat take care of the order, and those individual functions take care of the actual process. Since we will be preparing, chewing and swallowing an apple and the orange (just the way you do them is different) we will have each child class we create (apple, orange, banana, etc.) have the same exact functions, but the process would be different. And the order would always be the same.

So let's finish the child class with all the needed functions.

class apple extends fruit
{

    protected function prepare()
    {
        echo "Washing the apple.<br />";
    }

    protected function chew()
    {
        echo "Biting the apple.<br />";
        echo "Chewing the apple.<br />";
    }

    protected function swallow()
    {
        echo "Swallowing the apple.<br />";
    }

}

And we should edit parent class, function eat to reflect the change and utilize these added functions.

public function eat()
{
    $this->prepare();
    $this->chew();
    $this->swallow();
}

We could go ahead and add a class variable to the child class 'fruit' so we could use that in the parent class.

protected $fruit = 'apple';

And we could add some magic functions: 'construct()' and 'destruct()' in the parent class which would inform us on how many apples we ate.

public function __construct()
{
    echo "Picking up a(n) {$this->fruit}.<br />\n";
}

public function __destruct()
{
    echo "We ate a total of {$this->amount} {$this->fruit}(s).<br />\n";
}

I want to point out here that if you have any magic functions defined in a parent class and those same magic classes redefined in the child class, the child class functions would over-ride the parent class functions. This is true to every kind of functions, not just magic functions. If a function is redefined in the child class, then that function will over-ride the same named function found in the parent class.

So now, our file looks like:

<?php
class fruit
{

    private $amount = 2;

    public function __construct()
    {
        echo "Picking up a(n) {$this->fruit}.<br />\n";
    }

    public function eat()
    {
        $this->prepare();
        $this->chew();
        $this->swallow();
    }

    public function amount($number)
    {
        if($number < 11)
        {
            $this->amount = $number;
        }
    }

    public function __destruct()
    {
        echo "We ate a total of {$this->amount} {$this->fruit}(s).<br />\n";
    }

}

class apple extends fruit
{

    protected $fruit = 'apple';

    protected function prepare()
    {
        echo "Washing the apple.<br />";
    }

    protected function chew()
    {
        echo "Biting the apple.<br />";
        echo "Chewing the apple.<br />";
    }

    protected function swallow()
    {
        echo "Swallowing the apple.<br />";
    }

}

$product = new apple();

$product->eat();
?>

And if we run that, we would get the following:

Picking up a(n) apple.
Washing the apple.
Biting the apple.
Chewing the apple.
Swallowing the apple.
We ate a total of 2 apple(s).

(NOTE: The order in which you define the 'construct()' and 'destruct()' doesn't matter. You could switch their places if you want to, just having 'construct()' first and 'destruct()' last, keeps it more organized and less confusing.)

2.1 Multiple Classes

Now, lets say that we are working with multiple classes which extend one class (like class 'apple', 'orange' and 'banana' extending class 'fruit'). So we also have a class named 'banana':

class banana extends fruit
{

    protected $fruit = 'banana';

    protected function prepare()
    {
        echo "Peeling the banana.<br />";
    }

    protected function chew()
    {
        echo "Biting the banana.<br />";
        echo "Chewing the banana.<br />";
    }

    protected function swallow()
    {
        echo "Swallowing the banana.<br />";
    }

}

So now we have two child classes to one parent class... class 'apple' and 'banana'. We won't always want to eat an apple or a banana, we would like to switch around once in a while between the two (gets a bit tiring eating the same fruit over and over again, doesn't it?)

We could make a form asking the user which fruit they want to eat, and based on their input, we would run the correct class. Instead of writing a form, lets just emulate the input VIA a variable.

$fruit = 'banana';

The way we would call on the correct class through the use of that variable:

$fruit = 'banana'; // OR $fruit = $_GET['fruit']; OR $fruit = $_POST['fruit'];

$product = new $fruit();

$product->eat();

That would display:

Picking up a(n) banana.
Peeling the banana.
Biting the banana.
Chewing the banana.
Swallowing the banana.
We ate a total of 2 banana(s).

Please note, that all the functions that are called on from the parent class and are supposed to be defined in the child class (like the prepare(), chew() and swallow() functions in our classes) needs to be defined in all of the child classes (if you have more then one).

Unfortunately, you may not extend more then one class. This means you will always have one parent that could have multiple children, but you can't have a child with multiple parents. (class child extends mom, dad is not possible 😟 )

2.2 Inheritance and Hierarchy

All of the members (functions, variables and constants) of a parent class (the class being extended) are inherited by the child class(es) (the class(es) extending the parent class). This means that all of the members that are not declared as private are made available to all of the parent's children.

You can though (if you ever need/want to) over-ride the inherited members in a child class. You would mainly do this if the inherited member is mainly the same for every module in the system, but there is one weird module which has that part, but it needs to be ran differently.

PHP is a single-inheritance language. Meaning you can't extend more then one class (as previously mentioned) to inherit member's of multiple classes. You can though extend a class which extends a different class and inherit members of multiple classes that way. Sort of a multi-level inheritance. So we have a grandparent, parent and child class in this case. For example: (not part of the tutorial file).

<?php
class grandparent
{

    function granny()
    {
        echo "Grandparent<br />";
    }

}

class mother extends grandparent
{

    function mommy()
    {
        echo "Parent<br />";
    }

}

class child extends mother
{

    function son()
    {
        echo "Child<br />";
    }

}

$family = new child();

$family->granny();
$family->mommy();
$family->son();
?>

The child class inherits the members of class 'mother' and class 'grandparent. That code would print the following:

Grandparent
Parent
Child

But if you try the following code to those classes:

$family = new mother();

$family->granny();
$family->mommy();
$family->son();

What you would notice now is that instead of instantiating the 'child' class, I'm instantiating the 'mother' class, and at the bottom there, I'm trying to access a member of the 'child' class. That particular member would fail since the 'mother' class does not inherit the members of the 'child' class just the same as the 'grandparent' class not inheriting the members of the 'mother' and 'child' class. If you run that code, here is what you would get.

Grandparent
Parent

Fatal error: Call to undefined method mother::son() in C:\xampp\htdocs\www\classesAndOop\family.php on line 36

3.0 Our File

At the end of this tutorial, our file should look like:

<?php
class fruit
{

    private $amount = 2;

    public function __construct()
    {
        echo "Picking up a(n) {$this->fruit}.<br />\n";
    }

    public function eat()
    {
        $this->prepare();
        $this->chew();
        $this->swallow();
    }

    public function amount($number)
    {
        if($number < 11)
        {
            $this->amount = $number;
        }
    }

    public function __destruct()
    {
        echo "We ate a total of {$this->amount} {$this->fruit}(s).<br />\n";
    }

}

class apple extends fruit
{

    protected $fruit = 'apple';

    protected function prepare()
    {
        echo "Washing the apple.<br />";
    }

    protected function chew()
    {
        echo "Biting the apple.<br />";
        echo "Chewing the apple.<br />";
    }

    protected function swallow()
    {
        echo "Swallowing the apple.<br />";
    }

}

class banana extends fruit
{

    protected $fruit = 'banana';

    protected function prepare()
    {
        echo "Peeling the banana.<br />";
    }

    protected function chew()
    {
        echo "Biting the banana.<br />";
        echo "Chewing the banana.<br />";
    }

    protected function swallow()
    {
        echo "Swallowing the banana.<br />";
    }

}

$fruit = 'banana';

$product = new $fruit();

$product->eat();
?>

3.1 Conclusion

In this tutorial we learned how to extend a class, how child class behaves with parent class, how we could have multiple children to one parent (but no multiple parents to a child) and how we could dynamically call on a class by using a variable.

This page was published on It was last revised on

0

0 Comments

  • Votes
  • Oldest
  • Latest