Leccion 31 de 75 12 min de lectura

Herencia

La herencia permite crear clases basadas en otras existentes, heredando sus propiedades y metodos. Esto promueve la reutilizacion de codigo y modela relaciones "es un/una".

¿Que es la herencia?

La herencia modela relaciones jerarquicas. Un Perro es un Animal, un Gerente es un Empleado. La clase hija hereda todo de la clase padre y puede agregar o modificar comportamiento.

PHP
<?php
declare(strict_types=1);

class Animal
{
    protected string $nombre;

    public function __construct(string $nombre)
    {
        $this->nombre = $nombre;
    }

    public function hacerSonido(): string
    {
        return 'Algun sonido';
    }
}

class Perro extends Animal
{
    public function hacerSonido(): string
    {
        return 'Guau!';
    }

    public function buscarPelota(): string
    {
        return "{$this->nombre} busca la pelota";
    }
}

$perro = new Perro('Rex');
echo $perro->hacerSonido();    // Guau!
echo $perro->buscarPelota();   // Rex busca la pelota

extends y parent::

Usamos extends para heredar y parent:: para llamar a metodos de la clase padre:

PHP
<?php
declare(strict_types=1);

class Empleado
{
    protected string $nombre;
    protected float $salario;

    public function __construct(string $nombre, float $salario)
    {
        $this->nombre = $nombre;
        $this->salario = $salario;
    }

    public function getSalario(): float
    {
        return $this->salario;
    }
}

class Gerente extends Empleado
{
    private float $bono;

    public function __construct(string $nombre, float $salario, float $bono)
    {
        parent::__construct($nombre, $salario); // Llamar constructor padre
        $this->bono = $bono;
    }

    public function getSalario(): float
    {
        return parent::getSalario() + $this->bono; // Extender funcionalidad
    }
}

$empleado = new Empleado('Ana', 2000);
echo $empleado->getSalario(); // 2000

$gerente = new Gerente('Luis', 3000, 500);
echo $gerente->getSalario();  // 3500
parent:: es fundamental

Siempre llama a parent::__construct() cuando la clase padre tiene constructor. Asi aseguras que se inicialice correctamente.

Sobrescritura de métodos

La clase hija puede sobrescribir metodos del padre para cambiar su comportamiento:

PHP
<?php
declare(strict_types=1);

class Vehiculo
{
    protected string $marca;

    public function __construct(string $marca)
    {
        $this->marca = $marca;
    }

    public function arrancar(): string
    {
        return 'Vehiculo arrancando';
    }
}

class Coche extends Vehiculo
{
    public function arrancar(): string
    {
        return "El coche {$this->marca} arranca con llave";
    }
}

class Moto extends Vehiculo
{
    public function arrancar(): string
    {
        return "La moto {$this->marca} arranca con boton";
    }
}

$coche = new Coche('Toyota');
$moto = new Moto('Honda');

echo $coche->arrancar(); // El coche Toyota arranca con llave
echo $moto->arrancar();  // La moto Honda arranca con boton

protected vs private

Recuerda: protected es accesible en clases hijas, private no:

PHP
<?php
declare(strict_types=1);

class Padre
{
    protected string $protegido = 'accesible';
    private string $privado = 'inaccesible';
}

class Hijo extends Padre
{
    public function mostrar(): void
    {
        echo $this->protegido; // OK
        // echo $this->privado; // Error: no accesible
    }
}

Ejemplo practico: Sistema de formas

PHP
<?php
declare(strict_types=1);

class Forma
{
    protected string $color;

    public function __construct(string $color)
    {
        $this->color = $color;
    }

    public function getArea(): float
    {
        return 0.0;
    }
}

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;
    }
}

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;
    }
}

$rectangulo = new Rectangulo(10, 5, 'azul');
$circulo = new Circulo(3, 'rojo');

echo $rectangulo->getArea(); // 50
echo $circulo->getArea();    // 28.27...
Herencia simple

PHP solo permite heredar de una clase. Para reutilizar codigo de multiples fuentes, veremos traits e interfaces en proximas lecciones.

Ejercicios

Ejercicio 1: Vehiculos

Crea una clase base Vehiculo con marca, modelo y metodo describir(). Crea clases Coche (con puertas) y Moto (con cilindrada) que sobrescriban describir().

Ver solucion
PHP
<?php
declare(strict_types=1);

class Vehiculo
{
    protected string $marca;
    protected string $modelo;

    public function __construct(string $marca, string $modelo)
    {
        $this->marca = $marca;
        $this->modelo = $modelo;
    }

    public function describir(): string
    {
        return "Vehiculo: {$this->marca} {$this->modelo}";
    }
}

class Coche extends Vehiculo
{
    private int $puertas;

    public function __construct(string $marca, string $modelo, int $puertas)
    {
        parent::__construct($marca, $modelo);
        $this->puertas = $puertas;
    }

    public function describir(): string
    {
        return "Coche: {$this->marca} {$this->modelo} ({$this->puertas} puertas)";
    }
}

class Moto extends Vehiculo
{
    private int $cilindrada;

    public function __construct(string $marca, string $modelo, int $cilindrada)
    {
        parent::__construct($marca, $modelo);
        $this->cilindrada = $cilindrada;
    }

    public function describir(): string
    {
        return "Moto: {$this->marca} {$this->modelo} ({$this->cilindrada}cc)";
    }
}

$coche = new Coche('Toyota', 'Corolla', 4);
$moto = new Moto('Honda', 'CBR', 600);

echo $coche->describir(); // Coche: Toyota Corolla (4 puertas)
echo $moto->describir();  // Moto: Honda CBR (600cc)

Ejercicio 2: Empleados

Crea Empleado con nombre y salarioBase. Crea Desarrollador que agregue lenguaje y un bono del 20% al salario. Crea Disenador con herramienta y bono del 15%.

Ver solucion
PHP
<?php
declare(strict_types=1);

class Empleado
{
    protected string $nombre;
    protected float $salarioBase;

    public function __construct(string $nombre, float $salarioBase)
    {
        $this->nombre = $nombre;
        $this->salarioBase = $salarioBase;
    }

    public function getSalario(): float
    {
        return $this->salarioBase;
    }

    public function getNombre(): string
    {
        return $this->nombre;
    }
}

class Desarrollador extends Empleado
{
    private string $lenguaje;

    public function __construct(string $nombre, float $salarioBase, string $lenguaje)
    {
        parent::__construct($nombre, $salarioBase);
        $this->lenguaje = $lenguaje;
    }

    public function getSalario(): float
    {
        return parent::getSalario() * 1.20; // +20% bono
    }

    public function getLenguaje(): string
    {
        return $this->lenguaje;
    }
}

class Disenador extends Empleado
{
    private string $herramienta;

    public function __construct(string $nombre, float $salarioBase, string $herramienta)
    {
        parent::__construct($nombre, $salarioBase);
        $this->herramienta = $herramienta;
    }

    public function getSalario(): float
    {
        return parent::getSalario() * 1.15; // +15% bono
    }
}

$dev = new Desarrollador('Ana', 3000, 'PHP');
$dis = new Disenador('Luis', 2800, 'Figma');

echo $dev->getSalario(); // 3600 (3000 + 20%)
echo $dis->getSalario(); // 3220 (2800 + 15%)

Ejercicio 3: Cuentas bancarias

Crea Cuenta con saldo y metodos depositar() y retirar(). Crea CuentaAhorro que agregue interes al depositar y CuentaCorriente que permita sobregiro hasta -500.

Ver solucion
PHP
<?php
declare(strict_types=1);

class Cuenta
{
    protected float $saldo;

    public function __construct(float $saldoInicial = 0)
    {
        $this->saldo = $saldoInicial;
    }

    public function depositar(float $cantidad): void
    {
        if ($cantidad > 0) {
            $this->saldo += $cantidad;
        }
    }

    public function retirar(float $cantidad): bool
    {
        if ($cantidad > 0 && $cantidad <= $this->saldo) {
            $this->saldo -= $cantidad;
            return true;
        }
        return false;
    }

    public function getSaldo(): float
    {
        return $this->saldo;
    }
}

class CuentaAhorro extends Cuenta
{
    private float $tasaInteres;

    public function __construct(float $saldoInicial = 0, float $tasaInteres = 0.02)
    {
        parent::__construct($saldoInicial);
        $this->tasaInteres = $tasaInteres;
    }

    public function depositar(float $cantidad): void
    {
        if ($cantidad > 0) {
            $interes = $cantidad * $this->tasaInteres;
            $this->saldo += $cantidad + $interes;
        }
    }
}

class CuentaCorriente extends Cuenta
{
    private float $limiteDescubierto = 500;

    public function retirar(float $cantidad): bool
    {
        if ($cantidad > 0 && ($this->saldo - $cantidad) >= -$this->limiteDescubierto) {
            $this->saldo -= $cantidad;
            return true;
        }
        return false;
    }
}

$ahorro = new CuentaAhorro(1000, 0.05);
$ahorro->depositar(100);
echo $ahorro->getSaldo(); // 1105 (1000 + 100 + 5% de 100)

$corriente = new CuentaCorriente(200);
$corriente->retirar(500); // Permite, sobregiro hasta -500
echo $corriente->getSaldo(); // -300

¿Te está gustando el curso?

Tenemos cursos premium con proyectos reales y soporte personalizado.

Descubrir cursos premium