Vemos lo que son las interfaces, para qué se utilizan y cómo trabajar con ellas en PHP5.
Las interfaces son un sistema bastante común, utilizado en programación orientada a objetos. Son algo así como declaraciones de funcionalidades que tienen que cubrir las clases que implementan las interfaces.

En una interfaz se definen habitualmente un juego de funciones que deben codificar las clases que implementan dicha interfaz. De modo que, cuando una clase implementa una interfaz, podremos estar seguros que en su código están definidas las funciones que incluía esa interfaz.

A la hora de programar un sistema, podemos contar con objetos que son muy diferentes y que por tanto no pertenecen a la misma jerarquía de herencia, pero que deben realizar algunas acciones comunes. Por ejemplo, todos los objetos con los que comercia unos grandes almacenes deben contar con la funcionalidad de venderse. Una mesa tiene poco en común con un calefactor o unas zapatillas, pero todos los productos disponibles deben implementar una función para poder venderse.

Otro ejemplo. Una bombilla, un coche y un ordenador son clases muy distintas que no pertenecen al mismo sistema de herencia, pero todas pueden encenderse y apagarse. En este caso, podríamos construir una interfaz llamada “encendible”, que incluiría las funcionalidades de encender y apagar. En este caso, la interfaz contendría dos funciones o métodos, uno encender() y otro apagar().

Cuando se define una interfaz, se declaran una serie de métodos o funciones sin especificar ningún código fuente asociado. Luego, las clases que implementen esa interfaz serán las encargadas de proporcionar un código a los métodos que contiene esa interfaz. Esto es seguro: si una clase implementa una interfaz, debería declarar todos los métodos de la interfaz. Si no tenemos código fuente para alguno de esos métodos, por lo menos debemos declararlos como abstractos y, por tanto, la clase también tendrá que declararse como abstracta, porque tiene métodos abstractos.

Código para definir una interfaz

Veamos el código para realizar una interfaz. En concreto veremos el código de la interfaz encendible, que tienen que implementar todas las clases cuyos objetos se puedan encender y apagar.

interface encendible{
public function encender();
public function apagar();
}

Vemos que para definir una interfaz se utiliza la palabra clave interface, seguida por el nombre de la interfaz y, entre llaves, el listado de métodos que tendrá. Los métodos no se deben codificar, sino únicamente declararse.

Implementación de interfaces

Ahora veamos el código para implementar una interfaz en una clase.

class bombilla implements encendible{
public function encender(){
echo “<br>Y la luz se hizo…”;
}

public function apagar(){
echo “<br>Estamos a oscuras…”;
}
}

Para implementar una interfaz, en la declaración de la clase, se debe utilizar la palabra implements, seguida del nombre de la interfaz que se va a implementar. Se podrían implementar varias interfaces en la misma clase, en cuyo caso se indicarían todos los nombres de las interfaces separadas por comas.

En el código de la clase estamos obligados a declarar y codificar todos los métodos de la interfaz.

Nota: en concreto, PHP 5 entiende que si una clase implementa una interfaz, los métodos de esa interfaz estarán siempre en la clase, aunque no se declaren. De modo que si no los declaramos explícitamente, PHP 5 lo hará por nosotros. Esos métodos de la interfaz serán abstractos, así que la clase tendrá que definirse como abstracta. Se puede encontrar más información sobre la abstracción en el artículo Métodos y clases abstractos en PHP 5.

Ahora veamos el código de la clase coche, que también implementa la interfaz encendible. Este código lo hemos complicado un poco más.

class coche implements encendible{
private $gasolina;
private $bateria;
private $estado = “apagado”;

function __construct(){
$this->gasolina = 0;
$this->bateria = 10;
}

public function encender(){
if ($this->estado == “apagado”){
if ($this->bateria > 0){
if ($this->gasolina > 0){
$this->estado = “encendido”;
$this->bateria –;
echo “<br><b>Enciendo…</b> estoy encendido!”;
}else{
echo “<br>No tengo gasolina”;
}
}else{
echo “<br>No tengo batería”;
}
}else{
echo “<br>Ya estaba encendido”;
}
}

public function apagar(){
if ($this->estado == “encendido”){
$this->estado = “apagado”;
echo “<br><b>Apago…</b> estoy apagado!”;
}else{
echo “<br>Ya estaba apagado”;
}
}

public function cargar_gasolina($litros){
$this->gasolina += $litros;
echo “<br>Cargados $litros litros”;
}
}

A la vista del anterior código, se puede comprobar que no hay mucho en común entre las clases bombilla y coche. El código para encender una bombilla era muy simple, pero para poner en marcha un coche tenemos que realizar otras tareas. Antes tenemos que ver si el coche estaba encendido previamente, si tiene gasolina y si tiene batería. Por su parte, el método apagar hace una única comprobación para ver si estaba o no el coche apagado previamente.

También hemos incorporado un constructor que inicializa los atributos del objeto. Cuando se construye un coche, la batería está llena, pero el depósito de gasolina está vacío. Para llenar el depósito simplemente se debe utilizar el método cargar_gasolina().

Llamadas polimórficas pasando objetos que implementan una interfaz

Las interfaces permiten el tratamiento de objetos sin necesidad de conocer las características internas de ese objeto y sin importar de qué tipo son… simplemente tenemos que saber que el objeto implementa una interfaz.

Por ejemplo, tanto los coches como las bombillas se pueden encender y apagar. Así pues, podemos llamar al método encender() o apagar(), sin importarnos si es un coche o una bombilla lo que hay que poner en marcha o detener.

En la declaración de una función podemos especificar que el parámetro definido implementa una interfaz, de modo que dentro de la función, se pueden realizar acciones teniendo en cuenta que el parámetro recibido implementa un juego de funciones determinado.

Por ejemplo, podríamos definir una función que recibe algo por parámetro y lo enciende. Especificaremos que ese algo que recibe debe de implementar la interfaz encendible, así podremos llamar a sus métodos enciende() o apaga() con la seguridad de saber que existen.

function enciende_algo (encendible $algo){
$algo->encender();
}

$mibombilla = new bombilla();
$micoche = new coche();

enciende_algo($mibombilla);
enciende_algo($micoche);

Si tuviéramos una clase que no implementa la interfaz encendible, la llamada a esta función provocaría un error. Por ejemplo, un CD-Rom no se puede encender ni apagar.

class cd{
public $espacio;
}
$micd = new cd();
enciende_algo($micd); //da un error. cd no implementa la interfaz encendible

Esto nos daría un error como este: Fatal error: Argument 1 must implement interface encendible in c:\www\ejphp5\funcion_encender.php on line 6. Queda muy claro que deberíamos implementar la interfaz encendible en la clase cd para que la llamada a la función se ejecute correctamente.