Curso de PHP
Herencia de objetos en PHP: extends, parent y sobrescritura
Por Víctor Peña · Publicado el

Hola, ¿cómo están? Continuando con el curso de PHP, hoy veremos la herencia, el segundo pilar de la programación orientada a objetos que pusimos en práctica en la lección anterior.
¡Empecemos!
Qué es la herencia
La herencia permite crear una clase a partir de otra, heredando sus propiedades y métodos. La clase original se llama padre o clase base; la nueva, hija o derivada.
La idea es evitar repetir código. Si Perro y Gato comparten casi todo lo que hace Mascota, no tiene sentido escribir dos veces lo mismo.
La palabra extends
<?php
class Mascota
{
public function __construct(
public string $nombre,
public int $edad,
) {}
public function describir(): string
{
return "{$this->nombre}, {$this->edad} años";
}
}
class Perro extends Mascota
{
public function ladrar(): string
{
return "¡Guau!";
}
}
$nupi = new Perro("Nupi", 3);
echo $nupi->describir(); // Nupi, 3 años ← heredado
echo $nupi->ladrar(); // ¡Guau! ← propio
Perro tiene todo lo de Mascota más lo suyo, sin haber copiado una sola línea.
Sobrescribir métodos
Una clase hija puede redefinir un método del padre para comportarse de otra forma:
<?php
class Gato extends Mascota
{
public function describir(): string
{
return "El gato {$this->nombre} tiene {$this->edad} años";
}
}
$michi = new Gato("Michi", 2);
echo $michi->describir(); // El gato Michi tiene 2 años
PHP usa siempre la versión más cercana al objeto: si la hija lo define, se usa el de la hija.
Reutilizar el método del padre con parent
Muchas veces no quieres reemplazar el comportamiento, sino ampliarlo. Para eso está parent:::
<?php
class Gato extends Mascota
{
public function describir(): string
{
return parent::describir() . " y es un gato";
}
}
echo (new Gato("Michi", 2))->describir(); // Michi, 2 años y es un gato
parent::describir() ejecuta la versión del padre y tú añades lo tuyo.
El constructor en la herencia
Aquí está el punto que más problemas da. Si la hija define su propio constructor, el del padre no se ejecuta automáticamente. Tienes que llamarlo tú:
<?php
class Perro extends Mascota
{
public function __construct(
string $nombre,
int $edad,
public string $raza,
) {
parent::__construct($nombre, $edad);
}
public function describir(): string
{
return parent::describir() . ", raza {$this->raza}";
}
}
$nupi = new Perro("Nupi", 3, "Bulldog");
echo $nupi->describir(); // Nupi, 3 años, raza Bulldog
Si olvidas parent::__construct(), las propiedades del padre quedan sin inicializar y obtendrás un error al usarlas. Es de los fallos más frecuentes al empezar con herencia.
El modificador protected
Ya vimos public y private. La herencia introduce el tercero:
| Modificador | Desde la propia clase | Desde una clase hija | Desde fuera |
|---|---|---|---|
public |
Sí | Sí | Sí |
protected |
Sí | Sí | No |
private |
Sí | No | No |
<?php
class Mascota
{
protected string $codigo = "MSC-000";
private string $secreto = "no visible";
public function __construct(public string $nombre) {}
}
class Perro extends Mascota
{
public function verCodigo(): string
{
return $this->codigo; // funciona: es protected
// return $this->secreto; // Error: es private
}
}
protected es lo que quieres cuando algo debe compartirse con las clases hijas pero no exponerse al exterior.
Comprobar la relación entre clases
<?php
$nupi = new Perro("Nupi", 3, "Bulldog");
var_dump($nupi instanceof Perro); // true
var_dump($nupi instanceof Mascota); // true, también es una Mascota
Esto es clave: un objeto de la clase hija también es de la clase padre. Es lo que permite tratar perros y gatos como mascotas, y es la base del polimorfismo que veremos en un par de lecciones.
Herencia en cadena
Una clase hija puede a su vez tener hijas:
<?php
class Animal { }
class Mascota extends Animal { }
class Perro extends Mascota { }
Perro hereda de Mascota, que hereda de Animal. Funciona, pero conviene no abusar: más de dos o tres niveles hace el código difícil de seguir, porque para entender una clase tienes que ir subiendo por toda la cadena.
PHP no admite herencia múltiple
Una clase solo puede extender una clase:
<?php
class Perro extends Mascota, Vendible { } // Error: no se puede
Es una limitación deliberada, porque la herencia múltiple genera ambigüedades. Cuando necesites compartir comportamiento entre clases que no están emparentadas, la solución son los traits y las interfaces, que veremos más adelante.
Impedir la herencia con final
Si una clase no debe extenderse, o un método no debe sobrescribirse:
<?php
final class Configuracion { } // nadie puede heredar de ella
class Pago
{
final public function procesar(): void { } // no se puede sobrescribir
}
Se usa cuando el comportamiento es crítico y no quieres que nadie lo altere por accidente.
Cuándo usar herencia y cuándo no
La herencia es potente pero se abusa de ella. La prueba para saber si corresponde es simple:
¿La clase hija es un tipo de la clase padre?
- Un
Perroes unaMascota. Herencia correcta. - Un
Motorno es unAuto, forma parte de él. Aquí no toca herencia: toca queAutotenga una propiedad de tipoMotor.
Eso segundo se llama composición, y en general se prefiere sobre la herencia. La regla que repiten los libros es «composición sobre herencia», y significa que antes de extender una clase te preguntes si no basta con que una contenga a la otra.
Un ejemplo práctico
<?php
declare(strict_types=1);
class Empleado
{
public function __construct(
protected string $nombre,
protected float $salarioBase,
) {}
public function calcularSalario(): float
{
return $this->salarioBase;
}
public function describir(): string
{
return "{$this->nombre}: " . number_format($this->calcularSalario(), 2);
}
}
class Vendedor extends Empleado
{
public function __construct(
string $nombre,
float $salarioBase,
private float $ventas,
private float $comision = 0.05,
) {
parent::__construct($nombre, $salarioBase);
}
public function calcularSalario(): float
{
return parent::calcularSalario() + ($this->ventas * $this->comision);
}
}
$ana = new Empleado("Ana", 4000);
$luis = new Vendedor("Luis", 3000, 50000);
echo $ana->describir() . "\n"; // Ana: 4,000.00
echo $luis->describir() . "\n"; // Luis: 5,500.00
Fíjate en algo elegante: describir() está escrito una sola vez en el padre, pero llama a calcularSalario(), que cada clase resuelve a su manera. Eso ya es polimorfismo en acción.
Errores comunes
- Olvidar
parent::__construct()cuando la hija define constructor. - Intentar acceder a propiedades
privatedel padre desde la hija. Usaprotected. - Cadenas de herencia demasiado profundas.
- Usar herencia donde correspondía composición. Aplica la prueba del «es un».
Para cerrar
La herencia evita repetir código y permite que las clases hijas especialicen el comportamiento del padre. Recuerda parent:: para reutilizar, protected para compartir con las hijas, y la pregunta del «es un» antes de decidir extender.
En la siguiente lección veremos las clases anónimas.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp