Lesson 14 - Interfaces in PHP
In the previous exercise, Solved tasks for OOP in PHP lessons 12-13, we've practiced our knowledge from previous lessons.
In the previous lesson, Solved tasks for OOP in PHP lessons 12-13, we put our knowledge of OOP into practice by making a simple visit counter application. Today, we'll be getting into some more theory, we're going to talk about interfaces and continue working with our Human class and its descendants.
Interface
An interface, in programming terms, represents the public methods exposed by a class. In other words, we are able to communicate with a class instance using interfaces without having any sort of contact with anything other than its public methods/members.
An interface can also be defined independently, from outside of the class. An interface does not contain implementation, only method heads. As the name suggests, all it is is an interface Once we create it, we can implement it in a class.
Let's give it a try! Create an interface in the class folder, despite the fact that it's technically not actually a class. Create a new file called ProgrammerInterface.php, and add the following lines to it:
interface ProgrammerInterface { public function program(); }
All we'll include in our ProgrammerInterface interface is the program() method. We could add more, but for our needs, this should be enough.
Now, let's move to our PhpProgrammer.php class. Just to make sure you all remember it what it does:
class PhpProgrammer extends Human { public $ide; public function __construct($firstName, $lastName, $age, $password, $ide) { $this->ide = $ide; parent::__construct($firstName, $lastName, $age, $password); } public function greet() { echo("Hello world! I'm $this->firstName"); } public function program() { echo("I'm programming in {$this->ide}..."); } }
The PhpProgrammer class inherits from the Human class, calls the parent constructor, overrides the greet() method, and adds a new method names program().
We already know that we can only inherit from a single class in PHP. However, are also able to implement any number of interfaces. We do this by implementing the ProgrammerInterface interface in the class declaration via the "implements" keyword.
class PhpProgrammer extends Human implements ProgrammerInterface
Remember classes are inherited, interfaces are implemented. It makes total sense because inheritance extends a class with a new implementation. Whereas, all an interface does, is force a class to contain some methods. We can implement as many interfaces as we want, separated by commas.
Let's create an instance of PhpProgrammer in index.php:
{PHP} require_once('classes/Human.php'); require_once('classes/ProgrammerInterface.php'); require_once('classes/PhpProgrammer.php'); $phpProgrammer = new PhpProgrammer('Thomas', 'Futile', 28, 'ilovemypassword', 'NetBeans'); echo('OK');
{PHP} class Human { public $firstName; public $lastName; public $age; private $tiredness = 0; public $id; private static $peopleCount = 0; private $password; public function __construct($firstName, $lastName, $age, $password) { $this->firstName = $firstName; $this->lastName = $lastName; $this->age = $age; self::$peopleCount++; $this->id = self::$peopleCount; $this->password = $password; } public function sleep($time) { $this->tiredness -= $time * 10; if ($this->tiredness < 0) $this->tiredness = 0; } public function run($distance) { if ($this->tiredness + $distance <= 20) $this->tiredness += $distance; else echo("I'm too tired."); } public function greet() { echo('Hi, my name is ' . $this->firstName); } protected function fullName() { return $this->firstName . ' ' . $this->lastName; } public function __toString() { return $this->firstName . ' - ' . $this->id; } public static function validPassword($password) { return (mb_strlen($password) >= 5); } }
{PHP} interface ProgrammerInterface { public function program(); }
{PHP} class PhpProgrammer extends Human implements ProgrammerInterface { public $ide; public function __construct($firstName, $lastName, $age, $password, $ide) { $this->ide = $ide; parent::__construct($firstName, $lastName, $age, $password); } public function greet() { echo("Hello world! I'm $this->firstName"); } public function program() { echo("I'm programming in {$this->ide}..."); } }
If you were to run the application, everything would work just like it did before. Now, move to the PhpProgrammer class and comment out the program() method. If you go back again to index, you'll see the following error message:
The message tells us that the PhpProgrammer class implements the interface even though it doesn't have all of the required methods. Now, uncomment the program() method.
Meaning of interfaces
Interfaces bring many benefits to everyday programming, of which I will list a few:
Method overriding
As you already know, they allow us to choose the methods shown by the class. Along with visibility modifiers (private), interfaces are another tool used to keep proper code functionality.
Detecting interface presence
Let's put our people into an array with a few PhpProgrammer and Human instances in index.php. We'll have the instances greet in the loop. Also, if the instance is a programmer, we'll make it code. Notice how I said programmer, not PhpProgrammer because what we're going to do is have the program determine whether the instances implement our interface:
{PHP} require_once('classes/Human.php'); require_once('classes/ProgrammerInterface.php'); require_once('classes/PhpProgrammer.php'); $people = array(); $people[] = new Human('Carl', 'Smith', 30, '123456'); $people[] = new PhpProgrammer('John', 'Newman', 24, 'passwordissword', 'Eclipse'); $people[] = new Human('Jack', 'Newman', 50, 'swordfish'); $people[] = new PhpProgrammer('Thomas', 'Moore', 28, 'correct horse battery staple', 'NetBeans'); $people[] = new Human('Maria', 'Newman', 32, 'justacceptmypasswordandstopshowingvalidationerrors'); foreach ($people as $human) { echo($human . '<br />'); if ($human instanceof ProgrammerInterface) { $human->program(); echo('<br />'); } }
{PHP} class Human { public $firstName; public $lastName; public $age; private $tiredness = 0; public $id; private static $peopleCount = 0; private $password; public function __construct($firstName, $lastName, $age, $password) { $this->firstName = $firstName; $this->lastName = $lastName; $this->age = $age; self::$peopleCount++; $this->id = self::$peopleCount; $this->password = $password; } public function sleep($time) { $this->tiredness -= $time * 10; if ($this->tiredness < 0) $this->tiredness = 0; } public function run($distance) { if ($this->tiredness + $distance <= 20) $this->tiredness += $distance; else echo("I'm too tired."); } public function greet() { echo('Hi, my name is ' . $this->firstName); } protected function fullName() { return $this->firstName . ' ' . $this->lastName; } public function __toString() { return $this->firstName . ' - ' . $this->id; } public static function validPassword($password) { return (mb_strlen($password) >= 5); } }
{PHP} interface ProgrammerInterface { public function program(); }
{PHP} class PhpProgrammer extends Human implements ProgrammerInterface { public $ide; public function __construct($firstName, $lastName, $age, $password, $ide) { $this->ide = $ide; parent::__construct($firstName, $lastName, $age, $password); } public function greet() { echo("Hello world! I'm $this->firstName"); } public function program() { echo("I'm programming in {$this->ide}..."); } }
Now run the application:
As a result, we printed out all of the people and when an instance is identified to be a programmer, we make it program as well. To do this, we used the instanceof operator which detects the presence of an interface.
Note: The numbers set after each person's names are their IDs, see previous lessons for details.
This approach allows us to identify whether an object in a variable contains a specific mechanism that we require. Regardless of whether there is a PhpProgrammer, JavaProgrammer or PunchedCardProgrammer instance in the variable. All we're interested in is whether the object implements the ProgrammerInterface interface.
Determining variable type
Using the instanceof operator, we can determine an instance's variable type. We simply ask for a specific instance type in a variable using plain OOP. Without the use of the instanceof operator, we'd have to do something like declaring a HUMAN_TYPE constant in PhpProgrammer with a value of "programmer". Then, if we wanted our programmer to be a chess player as well, we'd run into issues once more. However, with instanceof all we'd have to do is implement another interface.
When identifying the presence a specified variable type, we are not limited to interfaces, we can also ask for a specific class. The code would work the same even if we set it up this way, although it would only be able to call on PhpProgrammer instances:
if ($human instanceof PhpProgrammer)
In this case, the class itself behaves just like an interface. Instanceof works even when if you were to use a class that has gone through several levels of inheritance.
Interfaces can do so much more in strongly typed languages, like Java. To be honest, I don't use them all that often in PHP. However, sometimes it's best to use them, especially when it comes to more complex class hierarchies.
Naming interfaces
Last of all, we'll go over naming interfaces. As all of you Java-heads out there may already know, PascalCase is one way to do it, as I have with all of my classes. There is, however, another conventional way of naming interfaces in PHP, which is adding the word "Interface" as a suffix.
You may also see interfaces out there with the -able suffix. For example, the DrawableInterface (something that can be drawn, i.e. forces implements the paint() method), SortableInterface, and so on.
In the next lesson, Interfaces and abstract classes in PHP, we will keep working with interfaces and will introduce you to what we call abstract classes. Today's code can be downloaded in the attachment below.
Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.
Download
By downloading the following file, you agree to the license terms
Downloaded 29x (4.29 kB)
Application includes source codes in language PHP