6. Las interfaces
Una interfaz es una estructura que define prototipos de métodos. Una clase que implementa una interfaz debe definir el código de todos los métodos de la interfaz.
6.1. El árbol de scripts

6.2. Una primera interfaz
Definimos una interfaz [IExemple] en un script [IExemple.php]. En este mismo script, definimos dos clases que implementan la interfaz [IExemple]:
<?php
// Cumplimiento estricto de los tipos de los parámetros de las funciones
declare(strict_types=1);
// espacio de nombres
namespace Exemples;
// una interfaz
interface IExemple {
// los métodos de la interfaz
public function ajouter(int $i, int $j): int;
public function soustraire(int $i, int $j): int;
}
// implementación 1 de la interfaz IExemple
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;
}
}
// implementación 2 de la interfaz IExemple
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;
}
}
Comentarios
- líneas 10-14: la interfaz IExemple define dos métodos: la función añadir (línea 12) y la función restar (línea 13). La interfaz no define el código de estos métodos. Son las clases que implementan la interfaz las que lo harán;
- línea 17: la clase Classe1 implementa la interfaz IExemple. Por lo tanto, define un código para los métodos «añadir» (línea 18) y «restar» (línea 22);
- líneas 29-38: lo mismo ocurre con la clase Classe2;
Utilizamos la interfaz [IExemple] en el siguiente script [interfaces-01.php]:
<?php
require_once "IExemple.php";
use \Exemples\Classe1;
use \Exemples\Classe2;
use \Exemples\IExemple;
// función
function calculer(int $a, int $b, IExemple $interface) : void {
print $interface->ajouter($a, $b)."\n";
print $interface->soustraire($a, $b)."\n";
}
// ------------------- main
// creación de 2 objetos de tipo Clase1 y Clase2
$c1 = new Classe1();
$c2 = new Classe2();
// llamada a la función calcular
calculer(4, 3, $c1);
calculer(14, 13, $c2);
Comentarios
- líneas 3-6: inclusión y definición de las clases e interfaces utilizadas por el script;
- línea 3: en lugar de la instrucción include, aquí hemos utilizado la instrucción require_once. La instrucción include incluye un archivo en el script actual aunque ya se haya incluido, mientras que la instrucción require_once solo lo incluye una vez. Por lo tanto, en lo que respecta a la inclusión de código, se prefiere la instrucción require_once;
- líneas 9-12: se define una función;
- línea 9: aquí hemos declarado el tipo de los tres parámetros. Si durante la ejecución el parámetro efectivo no es del tipo esperado, se lanza un error. El tercer parámetro es de tipo [IExemple]. Esto significa que el parámetro efectivo debe ser una instancia de una clase que implemente la interfaz [IExemple], por lo que, en nuestro ejemplo, una instancia de las clases [Classe1] o [Classe2];
- líneas 10-11: utilizamos los métodos [ajouter, soustraire] de la interfaz [IExemple];
- línea 19: el tercer parámetro efectivo es de tipo [Classe1], compatible con el tipo [IExemple] del tercer parámetro formal de la función;
- línea 20: lo mismo para la clase [Classe2];
Resultados
6.3. Derivación de una interfaz
Del mismo modo que una clase hija puede extender una clase padre, una interfaz hija puede extender una interfaz padre.
Consideremos la interfaz [IExemple2] definida en el archivo [IExemple2.php]:
<?php
// cumplimiento estricto de los tipos de los parámetros de las funciones
declare(strict_types=1);
// espacio de nombres
namespace Exemples;
// Inclusión de la definición de la interfaz IExemple
require_once __DIR__."/IExemple.php";
// una interfaz que deriva de IExemple
interface IExemple2 extends IExemple {
// el método de la interfaz
public function multiplier(int $i, int $j): int;
}
// implementación de la interfaz IExemple2
class Classe3 extends Classe2 implements IExemple2 {
public function multiplier(int $a, int $b): int {
return $a * $b;
}
}
Comentarios
- línea 6: la interfaz [IExemple2] estará en el mismo espacio de nombres que la interfaz [Iexemple];
- línea 9: se incluye el archivo de definición de la interfaz [Iexemple];
- líneas 12-15: definen la interfaz [IExemple2], que extiende (hereda) la interfaz [Iexemple] y le añade un nuevo método (línea 14);
- líneas 18-24: la clase [Classe3] extiende la clase [Classe2]. Dado que esta implementa la interfaz [IExemple], también lo hará la clase [Classe3]. De hecho, [Classe3] hereda todos los métodos públicos y protegidos de la clase [Classe2], es decir, los métodos «añadir» y «restar». Por otra parte, se indica que [Classe3] implementa la interfaz [IExemple2]. Como tal, también debe implementar el método «multiplier», algo que no hace [Classe2]. Esto es lo que hacen las líneas 20-22;
La interfaz [IExemple2] es utilizada por el siguiente script [interfaces-02]:
<?php
// Cumplimiento estricto de los tipos de los parámetros de las funciones
declare(strict_types=1);
// Inclusión y calificaciones de las clases e interfaces necesarias para el script
require_once __DIR__."/Iexemple2.php";
use \Exemples\IExemple2;
use \Exemples\Classe3;
// función
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";
}
// ------------------- main
// creación de 1 objeto de tipo Clase3 que implementa IExemple2
$c3 = new Classe3();
// llamada a la función calcular
calculer(4, 3, $c3);
Comentarios
- línea 12: el tercer parámetro de la función [calculer] es de tipo [IExemple2];
- líneas 13-15: se utilizan los tres métodos de la interfaz [IExemple2];
- línea 22: se llama a la función [calculer] con un objeto de tipo [IExemple2] (línea 20) como tercer parámetro;
Resultados
6.4. Pasar una interfaz como parámetro de una función
Hemos visto en el apartado anterior que, cuando el tipo esperado para un parámetro de función es una clase, el parámetro efectivo puede ser un objeto del tipo esperado o derivado. Lo mismo ocurre con las interfaces, como muestra el siguiente script [interfaces-03.php]:
<?php
// Cumplimiento estricto de los tipos de los parámetros de las funciones
declare(strict_types=1);
// Inclusión y calificaciones de las clases e interfaces necesarias para el script
require_once __DIR__."/IExemple.php";
use \Exemples\IExemple;
require_once __DIR__."/IExemple2.php";
use \Exemples\Classe3;
// función
function calculer(int $a, int $b, IExemple $interface) {
print $interface->ajouter($a, $b) . "\n";
print $interface->soustraire($a, $b) . "\n";
}
// ------------------- main
// creación de 1 objeto de tipo Classe3 que implementa IExemple2 y, por lo tanto, IExemple
$c3 = new Classe3();
// llamada a la función calcular
calculer(4, 3, $c3);
Comentarios
- línea 13: la función [calculer] espera como tercer parámetro un tipo [IExemple]. Esto significa que el tipo del parámetro efectivo podrá ser de tipo [IExemple] o derivado;
- línea 20: se instancia un objeto $c3 de tipo [Classe3], clase que implementa la interfaz [IExemple2], la cual a su vez extiende la interfaz [IExemple]. Por lo tanto, finalmente $c3 implementa la interfaz [IExemple];
- línea 22: se llama a la función [calculer] con un objeto $c3 de tipo [Classe3] como tercer parámetro. Mediante el juego de herencias de clases e implementaciones, hemos visto que el objeto $c3 implementaba el tipo [IExemple]. Por lo tanto, podemos utilizarlo como tercer parámetro;
Resultados