Herencia¶
PHP soporta herencia simple, de manera que una clase solo puede heredar de otra, no de dos clases a la vez. Para ello se utiliza la palabra clave extends
. Si queremos que la clase A herede de la clase B, se hará de la siguiente forma:
class A extends B
classDiagram
class A {
+atributo1
+metodo1()
}
class B {
+atributo2
+metodo2()
}
A <|-- B
El hijo hereda los atributos y métodos públicos y protegidos.
Cada clase en un archivo
Como ya hemos comentado, deberíamos colocar cada clase en un archivo diferente para posteriormente utilizarla mediante include
. En el siguiente ejemplo, se han colocado juntas para facilitar su legibilidad.
Por ejemplo, tenemos una clase Producto
y una Tv
que hereda de Producto
:
<?php
class Producto {
public $codigo;
public $nombre;
public $nombreCorto;
public $PVP;
public function mostrarResumen() {
echo "<p>Prod:".$this->codigo."</p>";
}
}
class Tv extends Producto {
public $pulgadas;
public $tecnologia;
}
Se pueden utilizar las siguientes funciones para averiguar si hay relación entre dos clases:
get_parent_class(object): string
is_subclass_of(object, string): bool
<?php
include 'ejemploHerencia.php';
$t = new Tv();
$t->codigo = 33;
if ($t instanceof Producto) {
echo $t->mostrarResumen();
}
$padre = get_parent_class($t);
echo "<br>La clase padre es: " . $padre;
$objetoPadre = new $padre;
echo $objetoPadre->mostrarResumen();
if (is_subclass_of($t, 'Producto')) {
echo "<br>Soy un hijo de Producto";
}
Sobreescribir métodos¶
Se pueden crear métodos en los hijos con el mismo nombre que el padre, cambiando su comportamiento. Para invocar a los métodos del padre parent::nombreMetodo()
<?php
class Tv extends Producto {
public $pulgadas;
public $tecnologia;
public function mostrarResumen() {
parent::mostrarResumen();
echo "<p>TV ".$this->tecnologia." de ".$this->pulgadas."</p>";
}
}
Constructor en hijos¶
En los hijos no se crea ningún constructor de manera automática. Por lo tanto, si no lo hay, se invoca automáticamente al del padre. En cambio, si se define en el hijo, se debe invocar al del padre de manera explícita.
<?php
class Producto {
public string $codigo;
public function __construct(string $codigo) {
$this->codigo = $codigo;
}
public function mostrarResumen() {
echo "<p>Prod:".$this->codigo."</p>";
}
}
class Tv extends Producto {
public $pulgadas;
public $tecnologia;
public function __construct(string $codigo, int $pulgadas, string $tecnologia) {
parent::__construct($codigo);
$this->pulgadas = $pulgadas;
$this->tecnologia = $tecnologia;
}
public function mostrarResumen() {
parent::mostrarResumen();
echo "<p>TV ".$this->tecnologia." de ".$this->pulgadas."</p>";
}
}
PHP 8 introdujo "promoción de propiedades del constructor", que te permite definir y asignar propiedades directamente desde los parámetros del constructo
<?php
class Producto {
public function __construct(private string $codigo) { }
public function mostrarResumen() {
echo "<p>Prod:".$this->codigo."</p>";
}
}
class Tv extends Producto {
public function __construct(
string $codigo,
private int $pulgadas,
private string $tecnologia)
{
parent::__construct($codigo);
}
public function mostrarResumen() {
parent::mostrarResumen();
echo "<p>TV ".$this->tecnologia." de ".$this->pulgadas."</p>";
}
}
$codigo
, $pulgadas
y tecnologia
, y las asigna.
Clases abstractas¶
Las clases abstractas obligan a heredar de una clase, ya que no se permite su instanciación. Se define mediante abstract class NombreClase
. Una clase abstracta puede contener propiedades y métodos no abstractos, y/o métodos abstractos.
<?php
// Clase abstracta
abstract class Producto {
private $codigo;
public function getCodigo() : string {
return $this->codigo;
}
// Método abstracto
abstract public function mostrarResumen();
}
Recordando clases abstractas
En el módulo profesional de Programación ya se introdujo el concepto de clase abstracta. Recuerda que, cuando una clase hereda de una clase abstracta, debe implementar obligatoriamente los métodos que el padre ha marcado como abstractos.
<?php
include 'AbstractProducto.php';
class Tv extends Producto {
public $pulgadas;
public $tecnologia;
public function mostrarResumen() { //obligado a implementarlo
echo "<p>Código ".$this->getCodigo()."</p>";
echo "<p>TV ".$this->tecnologia." de ".$this->pulgadas."</p>";
}
}
$t = new Tv();
echo $t->getCodigo();
Clases finales¶
Son clases opuestas a las abstractas, ya que evitan que se pueda heredar una clase o método para sobreescribirlo.
<?php
class Producto {
private $codigo;
public function getCodigo() : string {
return $this->codigo;
}
final public function mostrarResumen() : string {
return "Producto ".$this->codigo;
}
}
// No podremos heredar de Microondas
final class Microondas extends Producto {
private $potencia;
public function getPotencia() : int {
return $this->potencia;
}
// No podemos implementar mostrarResumen()
}
Actividades¶
Sobre las actividades
A lo largo de estas actividades, vamos a trabajar progresivamente con las clases Persona
y Empleado
, refinando su definición y ampliando su funcionalidad. Partiremos de una estructura básica, y paso a paso iremos incorporando conceptos clave de la programación orientada a objeto.
-
AC 308. (RA3 / CE3b CE3d / IC1 / 3p) - Se ha de realizar una copia del ejercicio AC307 y realizar una serie de modificaciones. Se ha de crear una clase
Persona
que sea padre deEmpleado
, de manera quePersona
contenga el nombre y los apellidos, y enEmpleado
quede el salario y los teléfonos. -
AC 309. (RA3 / CE3b CE3d / IC1 / 3p) - Se deben realizar modificaciones en AC308. Debemos implementar en
Persona
el método estáticotoHtml(Persona $p)
, y modificar enEmpleado
el mismo métodotoHtml(Persona $p)
, pero debemos cambiar la firma para que reciba unaPersona
como parámetro. Para acceder a las propiedades del empleado con la persona que se reciben como parámetro, debemos de comprobar su tipo<?php class Empleado extends Persona { /// resto del código public static function toHtml(Persona $p): string { if ($p instanceof Empleado) { // Aqui ya podemos acceder a las propiedades y métodos de Empleado } } }
-
AR 310. (RA3 / CE3b CE3d CE3g / IC1 / 3p) - Nos han solicitado una serie de modificaciones sobre AC309. En
Persona
se ha de añadir un atributoedad
. A la hora de saber si un empleado debe pagar impuestos, lo hará siempre y cuando tenga más de 21 años y dependa del valor de su sueldo. Se ha de modificar todo el código necesario para mostrar y/o editar la edad cuando sea necesario. -
AP 311. (RA3 / CE3b CE3d CE3g / IC1 / 3p) - Siguiendo con las mejoras en las clases
Persona
yEmpleado
, debemos añadir nuevos métodos que hagan una representación de todas las propiedades, de forma similar a los realizados en HTML, pero sin que sean estáticos, de manera que obtenga los datos mediante$this
.function public __toString(): string
-
PR 312. (RA3 / CE3b CE3c CE3d CE3g / IC2 / 5p) - El CTO del proyecto necesita empezar con él. Para ello se ha de diseñar un programa que contenga las siguientes clases:
Persona
,Producto
,Carrito
yPedidoComercial
. Una vez realizado esto, se han de generar las clases:EmpleadoTienda
,Comercial
yCliente
que heredan dePersona
.Pedido
que hereda deCarrito
.