Lesson 8 - Polymorphism, final attributes and autoloader in PHP

PHP OOP Polymorphism, final attributes and autoloader in PHP

In the previous lesson, Inheritance in PHP, we talked about inheritance and inherited the PhpProgrammer class from the Human class. Today, we're going to continue on a similar - polymorphism.

Polymorphism

Don't worry, although the term may sound intimidating, it's really quite simple. Polymorphism allows for you to use a unified interface to work with various object types. For example, imagine that we have many objects representing geometric shapes (circles, squares, triangles). It would be undoubtedly easier if we communicated with them in a way that they all understood. Despite the fact that they are not the same. We would start out by making a GeometricShape class, which would have a $color property and a draw() method. Then, we would make every geometric shape inherit this interface from the class. You may be asking yourselves, but wouldn't it end up drawing them all out the same? Wel, don't jump the gun, guy, I was getting to that. Polymorphism allows us to override the draw() method for every subclass. This way, it does what we want it to, when we want it to. The interface stays the same, which lets us focus on the task at hand.

Polymorphism is often explained on a picture with animals, where each of them has a speak() method that they take from a common interface and implement differently.

Polymorphism

The key principle of polymorphism is a method or methods that every descendant has declared with the same head, but with a different body. Let's try it out on our humans.

Greet

Our Human class' greet() method currently prints out a message like this:

Hi, I am Carl Smith

Human descendants inherit this method, i.e. PhpProgrammer. What we'll do is override the inherited method to make the descendant greet in a different way than a regular human.

Overriding methods

Overriding is easy, all you have to do is re-declare it in the descendant. Let's make our PhpProgrammer greet in a "programmer-ish" fashion by adding the greet() method to the PhpProgrammer class:

public function greet()
{
        echo("Hello world! I'm $this->firstName");
}

Now let's update index.php. To truly get grasp the benefits of polymorphism, we'll put several Human and PhpProgrammer instances into an array:

$people = array();
$people[] = new Human('Carl', 'Smith', 30);
$people[] = new PhpProgrammer('John', 'Newman', 24, 'Eclipse');
$people[] = new Human('Jack', 'Newman', 50);
$people[] = new PhpProgrammer('Thomas', 'Moore', 28, 'NetBeans');
$people[] = new Human('Maria', 'Newman', 32);

Now we'll make each of them greet. Since we used polymorphism, we'll be able to call the method for all of them in the same way:

foreach ($people as $human)
{
        $human->greet();
        echo('<br />');
}

The results are as expected:

Your page
localhost

Polymorphism advantages

Polymorphism is a very clear and beneficial programming technique. As you can see, we completely avoided any branching (conditions). We don't have to use "ifs" anywhere to determine whether an instance is a Human or a PhpProgrammer. Imagine if we had 100 Human descendants, branching would be an absolute disaster. This way, we can keep things organized and readable by keeping each individual descendant's logic contained in its own class. Working with multiple instances of various types has never been so easy. Polymorphism is useful when working with single instances as well, to avoid branching among other things.

A descendant can decide whether it overrides a method or keeps it as is. By writing programs in an object-oriented way, you save yourself from implementing complicated constructions, i.e. wide branching, nested loops, etc.

"final" keyword

In PHP, we use the "final" keyword to prevent other classes from inheriting from the class or overriding its methods. Although regular use of this technique is questionable, I'll show you how it's done in case you encounter it someday.

Final methods

We can prevent method overriding by marking the method as final in a parent class. Afterward, a descendant won't be able to override the method. Let's test it out on our Human class' greet() method:

public final function greet()
{
        echo("Hi, I am $this->firstName");
}

If you try to run the script, PHP will report a fatal error because the descendant, PhpProgrammer, tried to override the final method:

Cannot override final method Human::greet() in...

Now remove the "final" keyword from the method declaration.

Final classes

We can also mark an entire class as final. In doing so, we entirely prevent it from being inherited. In other words, the class won't be able to have descendants:

final class Human
{

        ...

}

Again, we'll get a Fatal error because our PhpProgrammer class still tries to inherit from the Human class:

Class PhpProgrammer may not inherit from final class (Human) in...

Final member overall meaning

As you already know, using final members is questionable. The original purpose of the "final" keyword was to completely prevent any and everything from inheriting or overriding specific application components. This could prove to be useful in enormous frameworks with many classes, where we might need force the application from becoming too complex. However, inappropriate use of the "final" keyword may result in redundant code. Personally, I think it's best NOT to use the final keyword at all.

Autoloading classes

Last of all, I'll give you all a nice little tweak, so you will no longer have to require classes manually. Using this neat little trick, you won't have to keep checking whether everything you need has been loaded, where failing to do so can result in many errors.

Old versions of PHP used the __autoload() magic method to autoload classes. However, there is a more modern way to do it (works with PHP 5.3 and up).

When we create a class instance (or we access a class statically, which we will get to later on in the course), PHP checks whether the class has already been loaded. What we will do, is register a function which will be called whenever PHP does the aforementioned check. We'll have PHP give us the unloaded class' name and load it using require().

Let's go back to the very beginning of index.php, where we will declare a function with an arbitrary name that only takes one parameter. Then, what we'll do is concatenate the unloaded class' name to our class folder's path and call require():

function loadClass($class)
{
        require("classes/$class.php");
}

Last of all, we tell PHP to call the function whenever it encounters an unloaded class:

spl_autoload_register("loadClass");

That's it! :) Now we can delete our require_once() from Human.php and PhpProgrammer.php. The application will still work as it did before and load new classes automatically whenever we add them. You only need one autoloader for the whole application, added somewhere at the start (usually in index.php). Class loading is now a thing of the past!

I'll be looking forward to seeing you all in the next lesson, Static class members in PHP, where we will learn about static members. Today's code can be found in the attachment below.


 

Download

Downloaded 16x (2.87 kB)
Application includes source codes in language PHP

 

 

Article has been written for you by David Capka
Avatar
Do you like this article?
1 votes
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn College The author learned IT at the Unicorn College - a prestigious college providing education on IT and economics.
Thumbnail
Previous article
Inheritance in PHP
Thumbnail
All articles in this section
Object-oriented programming in PHP
Activities (9)

 

 

Comments

To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

No one has commented yet - be the first!