jairogarcíarincón

Herencia, Extensión y Polimorfismo


9.57K

Introducción

Cuando empezamos a profundizar en el uso de clases es cuando apreciamos la potencia de la programación orientada a objetos.

En este apartado vamos a ver cómo podemos mejorar nuestras clases para que sean mucho más versátiles y nos sirvan para más cosas, y para ello partiremos de los conceptos de herencia, extensión y polimorfismo.


Herencia y Extensión

Según el sitio oficial de PHP:

"La herencia es un principio de programación bien establecido y PHP hace uso de él en su modelado de objetos. Este principio afectará la manera en que muchas clases y objetos se relacionan unas con otras.

Por ejemplo, cuando se extiende una clase, la subclase hereda todos los métodos públicos y protegidos de la clase padre. A menos que una clase sobrescriba esos métodos, mantendrán su funcionalidad original.

Esto es útil para la definición y abstracción de la funcionalidad y permite la implementación de funcionalidad adicional en objetos similares sin la necesidad de reimplementar toda la funcionalidad compartida."


Dicho de otro modo, mediante el uso de la herencia vamos a poder cambiar la morfología de la clase, extendiéndola para adaptarla a uestras necesidades concretas.

Para verlo en forma de ejemplo, vamos a suponer en la siguiente ampliación para nuestro desarrollo de coches:


  • Estaba pensado para la gestión de vehículos de un parking de 2 plantas subterráneas más una de superficie.

  • Ahora se va a ampliar su uso a furgonetas y autobuses.

  • Los autobuses no pueden aparcar en las plantas subterráneas pero sí en la superficie y además debo conocer el nombre de la empresa propietaria.

  • Las furgonetas solo pueden aparcar en la primera planta subterránea o en superficie y además debo conocer la altura.

  • Los coches solo pueden aparcar en las plantas subterráneas pero no en la superficie.



Una posible solución podría pasar por realizar las siguientes acciones:


  • Modificar la clase Coche (y su archivo correspondiente) para que ahora se llame Vehículo.

  • Añadir el atributo planta y sus correspondientes get() y set() para hacer referencia a la planta en la que estaciona el vehículo (aunque no aparezca en el constructor al no saber en qué planta estará el coche).

  • Añadir los atributos planta y plantas con un array que incluya las diferentes plantas disponibles.

  • Crear las clases Autobus, Furgoneta y Coche que extiendan la clase Vehiculo e incorporen el método puedeAparcar() para comprobar si puede o no puede aparcar, en función de la planta de entrada (este método se llamará igual pero será diferente en cada clase).

  • Añadir a la clase Autobus el atributo empresa y sobre-escribir el constructor para que incluya dicho atributo.



La clase Vehiculo.php:


<?php

class Vehiculo
{
//Variables o atributos
var $marca;
var $modelo;
var $color;
var $propietario;
var $planta;
var $plantas = array("superficie","subterraneo1","subterraneo2");

function __construct($miMarca,$miModelo,$miColor,$miPropietario){

$this->marca = $miMarca;
$this->modelo = $miModelo;
$this->color = $miColor;
$this->propietario = $miPropietario;

}

//Funciones o métodos
function setMarca($miMarca){

$this->marca = $miMarca;

}

function getMarca(){

return $this->marca;

}

function setModelo($miModelo){

$this->modelo = $miModelo;

}

function getModelo(){

return $this->modelo;

}

function setColor($miColor){

$this->color = $miColor;

}

function getColor(){

return $this->color;

}

function setPropietario($miPropietario){

$this->propietario = $miPropietario;

}

function getPropietario(){

return $this->propietario;

}

function setPlanta($miPlanta){

$this->planta = $miPlanta;

}

function getPlanta(){

return $this->planta;

}
}



La clase Autobus.php:


<?php
//Requiero el archivo de clase para extenderlo en este script
require_once("Vehiculo.php");

class Autobus extends Vehiculo
{
var $empresa;

function __construct($miMarca,$miModelo,$miColor,$miPropietario,$miEmpresa){

$this->marca = $miMarca;
$this->modelo = $miModelo;
$this->color = $miColor;
$this->propietario = $miPropietario;
$this->empresa = $miEmpresa;

}

//Funciones o métodos
function setEmpresa($miEmpresa){

$this->empresa = $miEmpresa;

}

function getEmpresa(){

return $this->empresa;

}


function puedeAparcar($miPlanta){

//True si está en el array y es superficie
return (array_search($miPlanta,$this->plantas) !== false && array_search($miPlanta,$this->plantas) == 0);

}


}



La clase Furgoneta.php:


<?php
//Requiero el archivo de clase para extenderlo en este script
require_once("Vehiculo.php");

class Furgoneta extends Vehiculo
{
function puedeAparcar($miPlanta){

//True si está en el array y no es subterraneo2
return (array_search($miPlanta,$this->plantas) !== false && array_search($miPlanta,$this->plantas) < 2);

}


}



La clase Coche.php:


<?php
//Requiero el archivo de clase para extenderlo en este script
require_once("Vehiculo.php");

class Coche extends Vehiculo
{
function puedeAparcar($miPlanta){

//True si está en el array y no es superficie
return (array_search($miPlanta,$this->plantas) !== false && array_search($miPlanta,$this->plantas) > 0);

}


}



El archivo index.php:


<?php
//Requiero los archivos de clase para incluirlos en este script
require("Autobus.php");
require("Furgoneta.php");
require("Coche.php");
?>

<h1>Ejemplo 4: Herencia, Extensión y Polimorfismo</h1>

<?php
//Instancio y configuro los vehículos
$autobus = new Autobus("Volvo","9800 2017","gris","Mario","Desfufor");
$furgoneta = new Furgoneta("Wolkswagen","Caravelle","blanco","Rebeca");
$coche = new Coche("Toyota","Corolla","verde","Marcos");
?>

<div>
¿Puedo aparcar el coche en la superficie?:
<strong><?php echo ($coche->puedeAparcar("superficie")) ? "si" : "no" ?></strong>
</div>
<div>
¿Puedo aparcar el coche en el subterráneo 2?:
<strong><?php echo ($coche->puedeAparcar("subterraneo2")) ? "si" : "no" ?></strong>
</div>
<div>
¿Puedo aparcar la furgoneta en la superficie?:
<strong><?php echo ($furgoneta->puedeAparcar("superficie")) ? "si" : "no" ?></strong>
</div>
<div>
¿Puedo aparcar la furgoneta el subterráneo 2?:
<strong><?php echo ($furgoneta->puedeAparcar("subterraneo2")) ? "si" : "no" ?></strong>
</div>
<div>
¿Puedo aparcar el autobús en la superficie?:
<strong><?php echo ($autobus->puedeAparcar("superficie")) ? "si" : "no" ?></strong>
</div>
<div>
¿Puedo aparcar el autobús el subterráneo 1?:
<strong><?php echo ($autobus->puedeAparcar("subterraneo1")) ? "si" : "no" ?></strong>
</div>
<div>
¿A qué empresa pertenece el autobús?:
<strong><?php echo $autobus->getEmpresa() ?></strong>
</div>



Y como siempre, vamos a analizar qué conclusiones podríamos extraer del ejemplo anterior:


  • Para extender una clase y poder acceder a todos sus métodos y atributos, tan solo tenemos que utilizar la directiva extends después del nombre de clase y añadir el nombre de la clase principal.

  • Los nombres de clases, variables o funciones nunca llevan tildes, caracteres extraños ni espacios, y no pueden empezar por un número.

  • No todos los atributos deben estar en el constructor, solo los necesarios para inicializar correctamente el objeto de clase.

  • Es posible sobre-escribir un atributo o método (incluyendo el constructor) en la clase secundaria simplemente declarándolo de nuevo en ella.

  • Al usar varias clases que extienden de la misma, es mejor utilizar require_once() para evitarnos la carga de la clase principal de nuevo.

  • A la hora de mezclar PHP con HTML, es mejor y más seguro frente a posibles inyecciones de código de tipo XSS incrustar el PHP dentro del HTML, esto es, abrir y cerrar las etiquetas de PHP en vez de hacer echos par el HTML.

  • Para PHP en una comparación, 0 y false es el mismo valor, lo que puede dar lugar a confusión.



Ejercicio propuesto 4


  • Modifica el Ejercicio 3 para poder realizar la gestión de contactos de un colegio.

  • Los alumnos deberán tener el atributo curso y un array de asignaturas (no todos las mismas) con sus métodos correspondientes.

  • Los profesores deberán tener los atributos salario y asignatura con sus métodos correspondientes.

  • El personal deberá tener el atributo salario con sus métodos correspondientes.

  • Realiza diferentes comprobaciones para ver si un alumno tiene cierta asignatura o no, o si un profesor gana más que otro o más que alguien del personal, o cómo el alumno a partir de una asignatura puede averiguar quién es su profesor.



Publicado el 21 de Noviembre de 2024