Classes and OOP (Part 6)

1.0 Previous Tutorial

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

First Tutorial
Second Tutorial
Third Tutorial
Fourth Tutorial
Fifth Tutorial

In the previous tutorial we learned about abstract classes, their relevance to the programming world and the difference between them and interfaces.

1.1 Tutorial Introduction

In this tutorial we will return to a topic previously touched and go more in detail: inheritance and hierarchy. We also going to learn about scope and their affect on OOP.

Like we touched previously in two tutorials (one about extending classes and the other about abstract classes) that all the child classes inherit the protected and public members (such as functions and variables), we are going to dwell a little longer and in more detail on it here... with emphasis on the hierarchy and how it plays a role in OOP.

This tutorial is pretty important as it sets up the foundation for the 7th tutorial in the series.

Since we're not going to be adding to or modifying our PHP tutorial example code in anyway, I'm going to leave it out from this tutorial to save space and prevent from cluttering up the tutorial with extra code that is not needed (and fill it up with extra sentences that are not needed 🤣 ).

2.0 Inheritance and Hierarchy

As we learned (and previously mentioned) that all classes have something to inherit... some, more than others. Child classes inherit everything that is protected or public from their parents, grandparents and farther up the hierarchy.

In the previous tutorials where I mentioned inheritance and (not) hierarchy, I actually failed to mention hierarchy. I want to do that here and define it so we would have a better mutual understanding on what that actually means in terms of PHP OOP (saying that because I don't know other languages and not sure if it is the same across different programming languages, though I imaging it would be).

In real life, a hierarchy is pretty much the entire family: grandparents, parents, children, grandchildren, nephews, uncles... so on and so on. Even adopted parents/children. Keeping that in mind, PHP has something similar, and everything inherits what is higher then them in the hierarchy tree (unless you're abstract, in which case you inherit everything that is higher up the hierarchy tree and lower).

Then we got your neighbours... most likely they are a different family with their own family tree (their own hierarchy). You won't really inherit anything from them (unless you are really good to them and they somehow end up putting you in their will). Even though you won't inherit anything between them, you still share the basic functions of life. The desire to live, the need to eat, sleep, pay taxes...

All of these similarities between different hierarchies are also present in the programming world and becomes pretty painful in PHP since PHP is a single inheritance language. Meaning you can't extend more then one class (more then one hierarchy) and in the process, inheriting their members. This is a topic for a whole new tutorial (which would be in part 7 so keep a look out, it's on its' way 🙂 )

The following is a hierarchy... one we've being working on (simplified to bare bones to make it smaller and easier to understand.

abstract class food
{

}

abstract class fruit extends food
{

}

class apple extends fruit
{

}

class banana extends fruit
{

}
?>

This is one hierarchy with class 'apple' inheriting the members of parent 'fruit' and grandparent 'food' and class 'banana' inheriting the members of parent 'fruit' and grandparent 'food'. Even though classes 'banana' and 'apple' are siblings, they don't share anything between them, so they don't inherit anything from each other.

Here is another hierarchy.

abstract class transportation
{

}

abstract class car extends transportation
{

}

class ford extends car
{

}

class toyota extends car
{

}

This is another hierarchy... a whole different set of classes that inherit it's own members, but not in the hierarchy that the class 'food' started. This is a whole different family with it's own dependencies and inheritances.

Even though both hierarchies don't really have anything in common (and don't share anything among each other), they still have some similarities. One of those similarities being the fact that they are used by and created for humans. They are also (in most cases) created by humans as well (though animals we hunt aren't created by humans).

Such similarities that are present in the programming language and requires the same code (or a template for a function [see dependencies below]) for each hierarchy, there is a way to do that (would be discussed in part 7 of the series). For those of you who're wondering what this is... it's called traits... these are the similarities, or similar traits between hierarchies that hierarchies share.

Inheritance is affected (as hinted before, and you might have found out by know) by certain access levels.

Public members are made available everywhere and (just about) everything inherits public members (since everything can access it) as long as you have an available object initiated.

Protected members are made available inside of a hierarchy only (and in some cases) only down the family tree (parents don't inherit child's members [this is true when a normal class extends a normal class]).

Private members are only available inside the class which defines it. Parents or children cannot touch private members. Even an abstract class may not touch a child's private member.

3.0 Scope

Believe it or not, but you already have experience with implementing scope in your code and may not know it. This may be true only if you don't know the definition of scope as it applies to programming. This was actually true to me until I started writing this part of this tutorial 🤣 I've being programming in PHP for years and didn't even knew of it's existence... yet I was using it everyday that I was coding.

This is one of those topics (scope is) which could've being talked about in a previous tutorial but is being talked here instead since all of the information we learned up to this point is affected by scope, and now that you know those information, it would be easier to explain scope. In addition, scope is dependent on that information we learned up to this point.

There are two kinds of scope that are present in PHP... Global and local scope.

You go between scopes with the help of curly brackets "{ ... }". Whatever is inside the curly brackets is considered to be part of a local scope (in most cases) and whatever is outside of the curly brackets is considered to be in global scope (again, in most cases). We are going to talk about this and the exceptions here.

Below is some code to put the definition/explenation in visual form (or an attempt to).

<?php
// Everything here is in global scope
$fruit = 'apple';

// A function
function food()
{ // The curly bracket telling us we are entering a local scope

    // Everything written in here is part of the local scope of this function

    echo $fruit;

} // The closing curly bracket telling us we are exiting the local scope

// Calling the function
food();
?>

If you run that code on your server you are going to get the following error.

Notice: Undefined variable: fruit in C:\xampp\htdocs\www\classesAndOop\scope.php on line 8

That would be because the variable $fruit was set and defined in global scope and when we created that function 'food()' we left the global scope of the page and entered the local scope of the function without passing it to the function. If we done something like the following:

<?php
// Everything here is in global scope
$fruit = 'apple';

// A function
function food($item)
{ // The curly bracket telling us we are entering a local scope

    // Everything written in here is part of the local scope of this function

    echo $item;

} // The closing curly bracket telling us we are exiting the local scope

// Calling the function
food($fruit);
?>

You would get the following because we are passing that variable from global scope to the local scope through the arguments of the class (as we have being doing in the classes we were writing in the previous examples (like the function 'amount()' for instance).

apple

A little later on in this tutorial we are going to discuss in more detail on how to pass variables to from global scope to local scope and back. (Reason for this is that that part of tutorial needs more information that would be opened up later on this tutorial).

3.1 Exceptions

It's not everywhere where the curly brackets exit global scope and enter a local scope. It's a good thing too, otherwise programming would be extremely frustrating and PHP would die out.

The curly brackets exit global scope and enter a local scope only in functions, classes, interfaces, abstract classes and traits (7th tutorial in the series).

Curly brackets does not exit global scope and enter a local scope in anything else. Imaging if the curly brackets meant you're in a local scope in a loop?

$fields = array('userID','username','email');
$i = 0;
while($row = mysqli_fetch_array($query))
{
    echo $row[$fields[$i]] . '<br />';

    $i++;
}

That code is an example code and does not display the best way to perform such action as defined in that code example.

The variables '$fields' and '$i' are defined outside of the loop and yet they are usable inside of the loop because the entire loop (and it's contents) are part of the global scope... those curly brackets just tell the script that you are inside the loop. Otherwise it would be hard to use the variable '$fields' inside the loop, unless you define it inside the loop, but that would be inefficient.

3.2 Scope Resolution Variable

Scope resolution variable is a variable that helps you retrieve members from a different scope to the current in a class. From one local scope to another.

In classes where you extend another class you might have the need to overwrite a function since it performs different then the parent class. This would be true if the function in parent class is written true to most of the children but with a few exceptions... a few child classes which needs that same function to be performed differently.

In some of those cases you wish you could simply extend on that function instead of overwriting it as this would save time and be easier. Well, you can with the help of scope resolution variable.

Here is an example of a scope resolution variable being put to use.

<?php
class world
{

    function speak()
    {
        return 'world!';
    }

}

class hello extends world
{

    function speak()
    {
        return 'Hello ' . parent::speak();
    }

}

class goodbye extends world
{

    function speak()
    {
        return 'Goodbye ' . parent::speak();
    }

}

$hi = new hello();
$bye = new goodbye();

echo $hi->speak();
echo '<br />';
echo $bye->speak();
?>

If you run that on your server, you would get the following result.

Hello world!
Goodbye world!

What you see there is that both of the child classes 'hello' and 'goodbye' are appending the parent's function 'speak()' to their function 'speak()' which are overwriting the parent's function.

Take notice that you are only able to extend on the return value of the 'parent::speak()' and are not able to affect the outcome of 'parent::speak()' in the child class function 'speak()'.

Maybe you don't want to extend (or elaborate) the parent function with the child function. Maybe the child function needs the method overwritten completely for a different purpose in most cases, but sometimes you might need the parent's version of the 'speak()' for some reason. For example:

<?php
class truth
{

    function execution()
    {
        return true;
    }

}

class lies extends truth
{

    function execution()
    {
        return false;
    }

    function opposite()
    {
        return parent::execution();
    }

}

$truth = new lies();

echo '<pre>';
var_dump($truth->execution());
echo '<br />';
var_dump($truth->opposite());
echo '</pre>';
?>

If you run that, you would get:

bool(false)

bool(true)

If we ever need to, we could also pass a variable to the parent member.

<?php
class nerd
{

    function get_punched($num)
    {
        return 'The class nerd was punched ' . $num . ' time(s).<br />';
    }

}

class bully extends nerd
{

    function get_punched($num)
    {
        return 'Then the class bully got punched ' . $num . ' time(s). Then came back and apologized!<br />';
    }

    function punch($num)
    {
        return parent::get_punched($num) . 'Then the class bully ran away laughing!<br />' . self::get_punched($num);

    }

}

$bully = new bully();

echo $bully->punch(4);
?>

That would display:

The class nerd was punched 4 time(s).
Then the class bully ran away laughing!
Then the class bully got punched 4 time(s). Then came back and apologized!

Here you would notice the introduction of a different variable... instead of parent:: now you see self:: included in there. Basically, it is the same as $this->. I can't think of why you would use self:: over $this-> unless you are accessing a class statically... which brings us to the next section.

3.3 Static Members in Scope

Classes accessed in a static context act a bit differently in OOP and have a different scope then any other kind of classes.

<?php
class citats
{

    private static function context()
    {
        return 'This is a static class.<br />';
    }

    public static function cite()
    {
        return 'Static spelled backwards would be citats.<br />' . self::context();
    }

}

echo citats::cite();
?>

First thing I want to point out is that when we use the class, we don't initiate it... we simply run it by having the class name, two colons '::' and the member name (could be variable, constant or function).

That is because static members are part of the global economy of the script run cycle. It's part of the global scope and is made available everywhere if you run it in a static context. When you call on members in a static context, you can't use the $this-> method, so '::' becomes useful.

No matter in which scope you are typing, local of a certain function or on the global scope, the class and it's members are made available for you statically without the need for initiation.

4.0 Sharing Members Between Hierarchies/Scopes

One problem programmers often face is passing variables from one scope to another to complete a function. Or passing some information from one hierarchy to another.

There are a few ways of accomplishing such feats but not all of them are great options (or even good). I'm going to mention them all, but there is a best option to accomplish it.

4.1 Passing as Argument

This is the most popular way of doing this, and the best way to do this. Passing variables from one scope to another through the help of arguments. (The comments are pretty important. Make sure you read them at least once).

<?php
// Variable set in global scope
$glad = true;

// Our class (Written in the global scope)
class feelings
{ // <-- Entering local scope of the class

    // The function... written in the local scope of the class
    public function feel($glad)
    { // <-- Entering local scope of the function
        // Some gibberish code to perform a useless task for example
        if($glad == true)
        { // <-- Not a scope marker... we could use variables set in the local scope of the function (or passed to the function)
            return 'Feeling Glad';
        }
        else
        {
            return 'Feeling Sad';
        }
    } // <-- Exiting local scope of the function and re-entering local scope of the class

} // <-- Exiting local scope of the class and re-entering global scope

// Our feeling object initiated
$feeling = new feelings;

// Passing the $glad variable from global scope to the local scope of the function inside the class object.
echo $feeling->feel($glad);
?>

As mentioned, this is the best way to pass variables from one scope to another.

4.2 Static Singletons

Since classes which can be accessed in a static context are always present in the global scope and doesn't need initiation, it is possible to collect variables into a static class and pass it from scope to scope without too much trouble.

A static class is not necessarily a singleton. A singleton is a programming pattern (for a later topic) which allows only 1 instance of such object. We'll talk about this later though.

For isntance, we have the following class (written for static contextual accessibility).

<?php
class citats
{

    public static $glad = true;
    public static $greedy = false;

}
?>

We are trying to pass those variables from that class to another... from one scope to another (and in essence, from one hierarchy to another). Since that class is always in global scope (static) and doesn't need initiation, it becomes a breeze.

// Our class (Written in the global scope)
class feelings
{ // <-- Entering local scope of the class

    // The function... written in the local scope of the class
    public function feel()
    { // <-- Entering local scope of the function
        // Some gibberish code to perform a useless task for example
        if(citats::$glad == true)
        { // <-- Not a scope marker... we could use variables set in the local scope of the function (or passed to the function)
            return 'Feeling Glad';
        }
        else
        {
            return 'Feeling Sad';
        }
    } // <-- Exiting local scope of the function and re-entering local scope of the class

} // <-- Exiting local scope of the class and re-entering global scope

$feeling = new feelings;

echo $feeling->feel();

You would notice the use of citats::$glad (on line 9). We didn't need to initiate anything, we simply use that static variable like it belonged there. This is not the best way to do this (the best way being passing it as an argument) but it's better then the following two ways.

4.3 Declaring as Global

We could pass a variable from one scope to another by declaring it as global in the local scope of the function we want to use it in. For instance (using our feelings class):

<?php
// Variable set in global scope
$glad = true;

// Our class (Written in the global scope)
class feelings
{ // <-- Entering local scope of the class

    // The function... written in the local scope of the class
    public function feel()
    { // <-- Entering local scope of the function
        // Declaring variable '$glad' as global
        global $glad;

        // Some gibberish code to perform a useless task for example
        if($glad == true)
        { // <-- Not a scope marker... we could use variables set in the local scope of the function (or passed to the function)
            return 'Feeling Glad';
        }
        else
        {
            return 'Feeling Sad';
        }
    } // <-- Exiting local scope of the function and re-entering local scope of the class

} // <-- Exiting local scope of the class and re-entering global scope

// Our feeling object initiated
$feeling = new feelings;

// Passing the $glad variable from global scope to the local scope of the function inside the class object.
echo $feeling->feel();
?>

As you would see there, we are not passing the variable '$glad' into the function or doing anything fun like that. We are simply declaring it global before we need to use it (which means it doesn't need to be at the beginning of the function... just once before you use it).

If you need to, you could declare more then one variable global by making a comma delimited list after the keyword global.

function some_func()
{
    global $var1, $var2, $var3; // ... and on and on and on
}

This is a terrible way to pass a variable from one scope to another since it creates dependencies and makes it hard later on in the code.

But the other ways creates dependencies as well... you still need those variables in order to pass them. That is true, but you don't need to worry about properly naming that variable you are passing and possibly naming a different variable elsewhere in the code by the same name.

4.4 Global Variable

PHP has a global variable (a pre-set variable) that is always set and allows you to access variables set in global scope everywhere as global. The variable is $GLOBAL. It is actually an array full of the variables that have being set in global scope. For example:

<?php
// Variable set in global scope
$glad = true;

// Our class (Written in the global scope)
class feelings
{ // <-- Entering local scope of the class

    // The function... written in the local scope of the class
    public function feel()
    { // <-- Entering local scope of the function
        // Some gibberish code to perform a useless task for example
        if($GLOBALS['glad'] == true)
        { // <-- Not a scope marker... we could use variables set in the local scope of the function (or passed to the function)
            return 'Feeling Glad';
        }
        else
        {
            return 'Feeling Sad';
        }
    } // <-- Exiting local scope of the function and re-entering local scope of the class

} // <-- Exiting local scope of the class and re-entering global scope

// Our feeling object initiated
$feeling = new feelings;

// Passing the $glad variable from global scope to the local scope of the function inside the class object.
echo $feeling->feel();
?>

You will notice on line 13 the use of the global variable ($GLOBAL['glad']). It makes the variable $glad which was set in global scope available in the local scope of the function.

Like I said, this way is terrible and it's even worse then declaring variables as globals since it creates the dependencies and on top of creating them, it tries to hide them in the code as well. Both forms of globalization (for a lack of better word) creates hidden dependencies, this way more then the other.

I recommend (as do many other programmers recommend) passing information from scope to scope through arguments as much as possible. At the very least use static classes, but passing as argument still is the best option.

5.0 Inherit Static

As it has being mentioned before, classes are written for a static context, rather then being written in a static context. You could access static function in an object context if you wanted to. For instance:

<?php

class test
{

    public static function test2()
    {
        return 'Test<br />';
    }

}

$testing = new test;
echo $testing->test2();
echo test::test2();

?>

If you run that code, you would see.

Test
Test

One test being printed from the object context and the other from the static context. Same class, but accessed differently.

Because of the global nature of classes accessed in a static context, they mess up the inheritance thing quite a bit. Or not really.

They don't really inherit anything extra, they are just available everywhere, making it seem like everything inherits them.

6.0 Dependencies

Dependency is the lack of freedom of a certain thing/object from something. (My own definition 🤣 )

In terms of OOP, you constantly create dependencies in your code, be it requested variables in argument list of a defined function, or the simple need of having a function and one that works.

Interfaces and abstract classes, for instance, creates dependencies when they leave a signature of an abstract function. Those functions need to be defined in the class extending them otherwise you will run into fatal errors.

This is not dependency in the truest of forms, but it is dependency of sorts. The parent class (an interface or an abstract class) depends on the child class to define that function that the parent class left as abstract and undefined.

In our third tutorial, we have created a dependency if you remember. (You could go back and check if you want to. Would be best visible in section 3.0 'Our File').

We had a main class named 'fruit' in which there was a function (named 'eat') utilizing three functions ('prepare', 'chew' and 'swallow') that were defined (or had to be defined) in the child class extending that class. Here is that class.

<?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";
    }

}
?>

And then the child classes ('apple' and 'banana') defined those functions. This was done by design specifically to be able to use and expandable system. We can now simply add more different kinds of fruits, have those functions defined and only use one function to eat any of them... 'eat'.

Not all dependencies are between classes. Some dependencies are between the scopes... local and global. A local scope of a function for instance, depends on the presence of a variable set in the global scope. To make matters worse, these kinds of dependencies are not always at first visible and may be very well hidden. I am talking about declaring variables as global or using the global variable of course.

// THE BAD
function some_function()
{
    global $ide, api, $nfx, $trd;

    // Code
}

// THE WORSE AND THE UGLY
function other_function()
{
    echo $GLOBAL['ide'] . $GLOBAL['api'] . $GLOBAL['nfx'] . $GLOBAL['trd'];
}

These sort of dependencies are even worse as they may be hidden (especially the $global variable) and makes it harder to debug your code (as well as add on to it later on).

This functions depends on the global scope to have those variables (named exactly like that) to be present. It is an ugly way to code and not at all elegant.

7.0 Conclusion

In this tutorial we covered a whole lot of information about inheritance, hierarchy, scope, static classes, passing of information and dependencies. This is a loaded tutorial 🤣

Let me stress some more on the fact that the best way to pass information between scope/hierarchies is through arguments and NOT static classes and ESPECIALLY not globals (both kinds).

This page was published on It was last revised on

0

0 Comments

  • Votes
  • Oldest
  • Latest