> Manuales > Orientación a objetos con PHP

Qué son las interfaces en programación en general y cómo se usan las interfaces en el lenguaje PHP, con ejemplos que nos ayuden a entender su utilidad.

Interfaces en PHP

Las interfaces son una de las herramientas más comunes en la Programación Orientada a Objetos. Debemos aprender a usarlas para sacarle todo el jugo a este paradigma de la programación, tanto en PHP como en cualquier otro lenguaje orientado a objetos.

En este artículo aprenderás qué son las interfaces, para qué pueden ser útiles y verás como crear interfaces en PHP y cómo implementarlas en tus clases.

Las interfaces fueron introducidas en PHP 5. En este artículo hacemos referencia a veces a esta versión del lenguaje, pero su funcionamiento ha permanecido inalterado hasta la fecha.

Qué son las interfaces

En términos generales y dentro de la programación orientada a objetos las interfaces son algo así como declaraciones de funcionalidades que tienen que cubrir las clases que las implementan.

A menudo nos referimos a ellas como "clases abstractas puras" en el sentido que son como clases abstractas en las que solamente hay declaraciones de métodos, pero no se expresa nunca la funcionalidad de ninguno de esos métodos.

Qué se puede definir dentro de una interfaz

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.

En una interfaz solamente podemos declarar métodos. Nunca propiedades. Además, todos los métodos que vamos a declarar en las interfaces deben tener visibilidad "public", ya que justamente la interfaz sirve para definir qué funcionalidades se encontrarán siempre disponibles en una clase determinada.

Para qué sirven las interfaces en la Programación Orientada a Objetos

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().

Gracias a las interfaces podemos aplicar técnicas de polimorfismo, mediante las cuales podemos suministrar objetos de jerarquías de herencia muy dispares pero que se sabe que se puede hacer unas cosas determinadas con ellos.

Al ser PHP un lenguaje levemente tipado no son tan fundamentales las interfaces, ya que a un método podríamos suministrar cualquier tipo de objeto. Pero a medida que PHP está introduciendo tipos, por ejemplo con el type hinting, para aportar de mayor seguridad a los desarrollos, las interfaces están cobrando más protagonismo. De todos modos, incluso sin pensar en tipos puede venirnos bien una interfaz en términos de diseño, para decirle al mundo las funcionalidades que se espera que suministre una clase.

Por cierto, si no sabes lo que es type hinting consiste simplemente en especificar en el parámetro que recibe un método el tipo de lo que esperas. En este mismo artículo veremos un ejemplo más tarde.

Obligar a definir todos los métodos de la interfaz en las clases que la implementan

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, de lo contrario deberá declararse como abstracta. Es decir, 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 en PHP

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. Luego, entre llaves, el listado de métodos que tendrá. Los métodos no se deben codificar, sino únicamente declararse.

Hay personas que cuando nombran una interfaz le ponen siempre el prefijo "i", por ejemplo "iEncendible". Esto no es necesario desde el punto de vista del lenguaje PHP. Ya que sea más útil o no colocarle ese prefijo, para que las personas que leen el código sepan que nos referimos a una interfaz, es una cuestión de interpretaciones o gustos. En mi caso particular lo veo totalmente innecesario y no lo considero una práctica recomendable, aunque tampoco veo que sea especialmente dañina.

Implementación de interfaces en PHP

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.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual