Clases Abstractas
Las clases abstractas son plantillas incompletas que definen metodos que las clases hijas deben implementar. No se pueden instanciar directamente.
¿Que es una clase abstracta?
Una clase abstracta define una estructura comun pero deja algunos metodos sin implementar. Estos metodos abstractos deben ser implementados por las clases hijas.
<?php
declare(strict_types=1);
abstract class Forma
{
protected string $color;
public function __construct(string $color)
{
$this->color = $color;
}
// Metodo abstracto: sin implementacion, solo firma
abstract public function getArea(): float;
// Metodo concreto: con implementacion
public function getColor(): string
{
return $this->color;
}
}
// $forma = new Forma('rojo'); // Error: no se puede instanciar clase abstracta
Implementar métodos abstractos
Las clases hijas deben implementar todos los metodos abstractos, o ser abstractas tambien:
<?php
declare(strict_types=1);
abstract class Forma
{
protected string $color;
public function __construct(string $color)
{
$this->color = $color;
}
abstract public function getArea(): float;
abstract public function getPerimetro(): float;
}
class Rectangulo extends Forma
{
private float $ancho;
private float $alto;
public function __construct(float $ancho, float $alto, string $color)
{
parent::__construct($color);
$this->ancho = $ancho;
$this->alto = $alto;
}
public function getArea(): float
{
return $this->ancho * $this->alto;
}
public function getPerimetro(): float
{
return 2 * ($this->ancho + $this->alto);
}
}
class Circulo extends Forma
{
private float $radio;
public function __construct(float $radio, string $color)
{
parent::__construct($color);
$this->radio = $radio;
}
public function getArea(): float
{
return M_PI * $this->radio ** 2;
}
public function getPerimetro(): float
{
return 2 * M_PI * $this->radio;
}
}
$rectangulo = new Rectangulo(10, 5, 'azul');
$circulo = new Circulo(3, 'rojo');
echo $rectangulo->getArea(); // 50
echo $circulo->getArea(); // 28.27...
echo $rectangulo->getColor(); // azul (metodo heredado)
Una clase abstracta puede tener metodos abstractos (sin cuerpo) y metodos concretos (con implementacion). Las clases hijas heredan los concretos y deben implementar los abstractos.
Ejemplo practico: Sistema de pagos
<?php
declare(strict_types=1);
abstract class MetodoPago
{
protected float $cantidad;
public function __construct(float $cantidad)
{
$this->cantidad = $cantidad;
}
abstract public function procesar(): bool;
abstract public function getNombre(): string;
public function getCantidad(): float
{
return $this->cantidad;
}
public function getResumen(): string
{
return "Pago de \${$this->cantidad} via {$this->getNombre()}";
}
}
class PagoTarjeta extends MetodoPago
{
private string $numeroTarjeta;
public function __construct(float $cantidad, string $numeroTarjeta)
{
parent::__construct($cantidad);
$this->numeroTarjeta = $numeroTarjeta;
}
public function procesar(): bool
{
// Logica de procesamiento de tarjeta
return strlen($this->numeroTarjeta) === 16;
}
public function getNombre(): string
{
return 'Tarjeta';
}
}
class PagoPayPal extends MetodoPago
{
private string $email;
public function __construct(float $cantidad, string $email)
{
parent::__construct($cantidad);
$this->email = $email;
}
public function procesar(): bool
{
// Logica de procesamiento PayPal
return filter_var($this->email, FILTER_VALIDATE_EMAIL) !== false;
}
public function getNombre(): string
{
return 'PayPal';
}
}
$tarjeta = new PagoTarjeta(99.99, '1234567890123456');
$paypal = new PagoPayPal(49.99, 'usuario@email.com');
echo $tarjeta->getResumen(); // Pago de $99.99 via Tarjeta
echo $paypal->getResumen(); // Pago de $49.99 via PayPal
if ($tarjeta->procesar()) {
echo 'Pago con tarjeta procesado';
}
¿Cuando usar clases abstractas?
- Cuando quieres definir una plantilla que otras clases deben seguir
- Cuando tienes codigo comun que compartir entre clases relacionadas
- Cuando algunas operaciones dependen del tipo especifico de clase hija
<?php
declare(strict_types=1);
abstract class Animal
{
protected string $nombre;
public function __construct(string $nombre)
{
$this->nombre = $nombre;
}
abstract public function hacerSonido(): string;
public function presentarse(): string
{
return "Soy {$this->nombre} y hago: {$this->hacerSonido()}";
}
}
class Perro extends Animal
{
public function hacerSonido(): string
{
return 'Guau!';
}
}
class Gato extends Animal
{
public function hacerSonido(): string
{
return 'Miau!';
}
}
$perro = new Perro('Rex');
$gato = new Gato('Michi');
echo $perro->presentarse(); // Soy Rex y hago: Guau!
echo $gato->presentarse(); // Soy Michi y hago: Miau!
Ejercicios
Ejercicio 1: Empleados
Crea una clase abstracta
Empleado con
nombre,
salarioBase y metodo
abstracto
calcularSalario(): float.
Implementa
EmpleadoFijo (salario =
base) y
EmpleadoPorHoras (salario =
horas * tarifa).
Ver solucion
<?php
declare(strict_types=1);
abstract class Empleado
{
protected string $nombre;
protected float $salarioBase;
public function __construct(string $nombre, float $salarioBase)
{
$this->nombre = $nombre;
$this->salarioBase = $salarioBase;
}
abstract public function calcularSalario(): float;
public function getNombre(): string
{
return $this->nombre;
}
}
class EmpleadoFijo extends Empleado
{
public function calcularSalario(): float
{
return $this->salarioBase;
}
}
class EmpleadoPorHoras extends Empleado
{
private int $horasTrabajadas;
public function __construct(string $nombre, float $tarifaHora, int $horas)
{
parent::__construct($nombre, $tarifaHora);
$this->horasTrabajadas = $horas;
}
public function calcularSalario(): float
{
return $this->salarioBase * $this->horasTrabajadas;
}
}
$fijo = new EmpleadoFijo('Ana', 2500);
$porHoras = new EmpleadoPorHoras('Luis', 15, 160);
echo $fijo->calcularSalario(); // 2500
echo $porHoras->calcularSalario(); // 2400
Ejercicio 2: Notificaciones
Crea Notificacion abstracta
con mensaje y metodo
abstracto enviar(): bool.
Implementa
NotificacionEmail y
NotificacionSMS
con sus propios atributos (email,
telefono).
Ver solucion
<?php
declare(strict_types=1);
abstract class Notificacion
{
protected string $mensaje;
public function __construct(string $mensaje)
{
$this->mensaje = $mensaje;
}
abstract public function enviar(): bool;
public function getMensaje(): string
{
return $this->mensaje;
}
}
class NotificacionEmail extends Notificacion
{
private string $email;
public function __construct(string $mensaje, string $email)
{
parent::__construct($mensaje);
$this->email = $email;
}
public function enviar(): bool
{
echo "Enviando email a {$this->email}: {$this->mensaje}\n";
return filter_var($this->email, FILTER_VALIDATE_EMAIL) !== false;
}
}
class NotificacionSMS extends Notificacion
{
private string $telefono;
public function __construct(string $mensaje, string $telefono)
{
parent::__construct($mensaje);
$this->telefono = $telefono;
}
public function enviar(): bool
{
echo "Enviando SMS a {$this->telefono}: {$this->mensaje}\n";
return strlen($this->telefono) >= 9;
}
}
$email = new NotificacionEmail('Bienvenido!', 'user@example.com');
$sms = new NotificacionSMS('Tu codigo: 1234', '+34666777888');
$email->enviar(); // Enviando email a user@example.com: Bienvenido!
$sms->enviar(); // Enviando SMS a +34666777888: Tu codigo: 1234
Ejercicio 3: Documentos
Crea Documento abstracta
con titulo, metodo concreto
getTitulo() y metodo
abstracto
exportar(): string.
Implementa DocumentoPDF y
DocumentoHTML que retornen
formatos diferentes.
Ver solucion
<?php
declare(strict_types=1);
abstract class Documento
{
protected string $titulo;
protected string $contenido;
public function __construct(string $titulo, string $contenido)
{
$this->titulo = $titulo;
$this->contenido = $contenido;
}
public function getTitulo(): string
{
return $this->titulo;
}
abstract public function exportar(): string;
}
class DocumentoPDF extends Documento
{
public function exportar(): string
{
return "[PDF] {$this->titulo}\n---\n{$this->contenido}\n---";
}
}
class DocumentoHTML extends Documento
{
public function exportar(): string
{
return "<html><head><title>{$this->titulo}</title></head>" .
"<body><h1>{$this->titulo}</h1><p>{$this->contenido}</p></body></html>";
}
}
$pdf = new DocumentoPDF('Informe', 'Contenido del informe...');
$html = new DocumentoHTML('Pagina', 'Contenido de la pagina...');
echo $pdf->exportar();
// [PDF] Informe
// ---
// Contenido del informe...
// ---
echo $html->exportar();
// <html><head><title>Pagina</title></head>...
¿Has encontrado un error o tienes una sugerencia para mejorar esta leccion?
Escribenos¿Te está gustando el curso?
Tenemos cursos premium con proyectos reales y soporte personalizado.
Descubrir cursos premium