Skip to content

6. Interfaces

An interface is a structure that defines method prototypes. A class that implements an interface must define the code for all of the interface’s methods.

6.1. The script tree

Image

6.2. A first interface

We define an interface [IExemple] in a script [IExemple.php]. In this same script, we define two classes that implement the interface [IExemple]:


<?php
 
// strict adherence to function parameter types
declare(strict_types=1);
 
// namespace
namespace Exemples;
 
// an interface
interface IExemple {
    // interface methods
    public function ajouter(int $i, int $j): int;
    public function soustraire(int $i, int $j): int;
}
 
// implementation 1 of the IExemple interface
class Classe1 implements IExemple {
    public function ajouter(int $a, int $b): int {
        return $a + $b + 10;
    }
 
    public function soustraire(int $a, int $b): int {
        return $a - $b + 20;
    }
 
}
 
// implementation 2 of the IExemple interface
class Classe2 implements IExemple {
    public function ajouter(int $a, int $b) : int{
        return $a + $b + 100;
    }
 
    public function soustraire(int $a, int $b) : int {
        return $a - $b + 200;
    }
 
}

Comments

  • lines 10–14: The IExemple interface defines two methods: the add function (line 12) and the subtract function (line 13). The interface does not define the code for these methods. The classes that implement the interface will do so;
  • line 17: the Class1 class implements the IExemple interface. It therefore defines code for the add method (line 18) and the subtract method (line 22);
  • lines 29–38: same for the Class2 class;

We use the [IExemple] interface in the following [interfaces-01.php] script:


<?php
 
require_once "IExemple.php";
use \Exemples\Classe1;
use \Exemples\Classe2;
use \Exemples\IExemple;
 
// function
function calculer(int $a, int $b, IExemple $interface) : void {
  print $interface->ajouter($a, $b)."\n";
  print $interface->soustraire($a, $b)."\n";
}
 
// ------------------- hand
// creation of 2 objects of type Class1 and Class2
$c1 = new Classe1();
$c2 = new Classe2();
// call the calculate function
calculer(4, 3, $c1);
calculer(14, 13, $c2);

Comments

  • lines 3–6: inclusion and definition of the classes and interfaces used by the script;
  • line 3: instead of the include statement, we used the require_once statement here. The include statement includes a file in the current script even if it has already been included, whereas the require_once statement includes it only once. Therefore, when it comes to including code, we prefer the require_once statement;
  • lines 9–12: we define a function;
  • line 9: here we have declared the type of the three parameters. If, at runtime, the actual parameter is not of the expected type, an error is thrown. The third parameter is of type [IExemple]. This means that the actual parameter must be an instance of a class implementing the [IExemple] interface; therefore, in our example, an instance of the classes [Classe1] or [Classe2];
  • lines 10–11: we use the [ajouter, soustraire] methods of the [IExemple] interface;
  • line 19: the third actual parameter is of type [Classe1], which is compatible with the type [IExemple] of the function’s third formal parameter;
  • line 20: same for class [Classe2];

Results

1
2
3
4
17
21
127
201

6.3. Deriving an Interface

Just as a child class can extend a parent class, a child interface can extend a parent interface.

Consider the [IExemple2] interface defined in the [IExemple2.php] file:


<?php
 
// strict adherence to function parameter types
declare(strict_types=1);
// namespace
namespace Exemples;
 
// interface definition IExemple included
require_once __DIR__."/IExemple.php";
 
// an interface derived from IExemple
interface IExemple2 extends IExemple {
    // the interface method
    public function multiplier(int $i, int $j): int;
}
 
// implementation of IExemple2 interface
class Classe3 extends Classe2 implements IExemple2 {
   
    public function multiplier(int $a, int $b): int {
        return $a * $b;
    }
 
}

Comments

  • line 6: the [IExemple2] interface will be in the same namespace as the [Iexemple] interface;
  • line 9: the definition file for the [Iexemple] interface is included;
  • lines 12–15: define the [IExemple2] interface, which extends (inherits from) the [Iexemple] interface and adds a new method to it (line 14);
  • lines 18–24: the class [Classe3] extends the class [Classe2]. Since the latter implements the [IExemple] interface, the [Classe3] class will also do so. In fact, [Classe3] inherits all the public and protected methods of the [Classe2] class, including the add and subtract methods. Furthermore, it is noted that [Classe3] implements the [IExemple2] interface. As such, it must also implement the multiply method, which [Classe2] does not do. This is what lines 20–22 do;

The [IExemple2] interface is used by the following [interfaces-02] script:


<?php
 
// strict adherence to function parameter types
declare(strict_types=1);
 
// inclusion and qualification of classes and interfaces required by the script
require_once __DIR__."/Iexemple2.php";
use \Exemples\IExemple2;
use \Exemples\Classe3;
 
// function
function calculer(int $a, int $b, IExemple2 $interface) {
    print $interface->ajouter($a, $b) . "\n";
    print $interface->soustraire($a, $b) . "\n";
    print $interface->multiplier($a, $b) . "\n";
}
 
// ------------------- hand
// creation of 1 Class3 object implementing IExemple2
$c3 = new Classe3();
// call the calculate function
calculer(4, 3, $c3);

Comments

  • line 12: the third parameter of the [calculer] function is of type [IExemple2];
  • lines 13–15: the three methods of the [IExemple2] interface are used;
  • line 22: the function [calculer] is called with an object of type [IExemple2] (line 20) as the third parameter;

Results

1
2
3
107
201
12

6.4. Passing an Interface as a Function Parameter

We saw in the previous section that when the expected type for a function parameter is a class, the actual parameter can be an object of the expected type or a derived type. The same applies to interfaces, as shown in the following script [interfaces-03.php]:


<?php
 
// strict adherence to function parameter types
declare(strict_types=1);
 
// inclusion and qualification of classes and interfaces required by the script
require_once __DIR__."/IExemple.php";
use \Exemples\IExemple;
require_once __DIR__."/IExemple2.php";
use \Exemples\Classe3;
 
// function
function calculer(int $a, int $b, IExemple $interface) {
  print $interface->ajouter($a, $b) . "\n";
  print $interface->soustraire($a, $b) . "\n";
}
 
// ------------------- hand
// creation of 1 object of type Class3 which implements IExemple2 and therefore IExemple
$c3 = new Classe3();
// call the calculate function
calculer(4, 3, $c3);

Comments

  • line 13: the function [calculer] expects a type [IExemple] as its third parameter. This means that the actual parameter type can be [IExemple] or a derived type;
  • line 20: we instantiate a $c3 object of type [Classe3], a class that implements the [IExemple2] interface, which itself extends the [IExemple] interface. So ultimately, $c3 implements the [IExemple] interface;
  • Line 22: The function [calculer] is called with a $c3 object of type [Classe3] as its third parameter. Through class inheritance and implementations, we saw that the $c3 object implements the [IExemple] type. We can therefore use it as the third parameter;

Results

107
201