Anthony Chambers

Engineer 81

Polymorphism through object inheritance

How to implement polymorphism in PHP through extending existing objects, rather than implementing an interface

Written by Anthony Chambers , and read6,596 times

In my post "Don't Inject Dependency Injection Containers", we refactored our code and made it polymorphic. The basics of polymorphism are to code to an interface, and not an implementation. We have covered this in a follow up article, "Polymorphism in PHP".

However, polymorphism is often described in PHP through examples of extending an abstract class, rather than implementing an interface. So, in the interests of completeness, I'm going to revisit the subject but put the inheritance twist on it instead of using PHP's interfaces.

If you haven't read the original post, I recommend that you do so before tackling this one as we refer to code written in it, but it isn't required.

So, in that original post we had a switch in our GreetingClass that covered all supported languages, ie DE, EN and FR. These were the classes that we had type-hinted in the constructor as well. We refactored the class to no longer depend on these concrete implementations, but instead to depend on an abstract concept; an interface.

Once we've done this, we no longer need to care about concrete implementations. We know that any object that is successfully passed in to our constructor MUST implement a hello() method. We know this because it is declared in the Language interface. So GreetingClass is now far more flexible, far simpler to read (and maintain), and because it will now work with ANY object that implements Language, it is now polymorphic.

Polymorphism is usually demonstrated with inheritance, so instead of having a Language interface, I would have a Language class, which would be abstract. The various language classes would then extend this class, something like this:

<?php
/**
 * Declare an abstract class which has our hello() functionality built in
 */
abstract class Language {
    protected $hello = "Undefined greeting";

    public function hello()
    {
        return $this->hello;
    }
}

/**
 * Deutsch extends Language, and sets $hello accordingly
 */
class Deutsch extends Language {
    protected $hello = 'hallo';
}

/**
 * English does the same as Deutsch, but with an English greeting
 */
class English extends Language {
    protected $hello = 'hello';
}

/**
 * And Francais does the same with a French greeting
 */
class Francais extends Language {
    protected $hello = 'bonjour';
}

$greeter = new GreetingClass(new Francais);
echo $greeter->hello(); // Prints "bonjour"

You may be surprised to see that this works with our original GreetingClass code. When you type-hint in PHP it will accept an interface or a class, and the class can be the specific class that you have passed in, or it could be one that is extended in the implementation, as it is in our example here. It is not possible to have loaded a class and an interface with the same name so you can be sure that it will accept only the one that you intended to use.

We're not technically coding to an interface any more in that an abstract class isn't technically an interface; it includes an actual implementation. However, our GreetingClass is still the same. It's still polymorphic. The principles are exactly the same, regardless of whether you are implementing an interface or extending a class.

So that's polymorphism with inheritance, in a nutshell.