Menu

Herencia en PHP: extends, parent:: y sobrescribir métodos

En PHP una clase hereda de otra con class Dog extends Animal: recibe las propiedades y los métodos públicos y protegidos del padre, puede sobrescribirlos y aun así llamar al original con parent::method(). Aprende la sobrescritura, protected, final, instanceof y la trampa de los métodos privados.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

En PHP una clase hereda de otra con extends: class Dog extends Animal le da a Dog todas las propiedades y métodos públicos y protegidos de Animal. La hija puede añadir métodos nuevos, sobrescribir los heredados declarando un método con el mismo nombre y llamar al original con parent::method().

Dog no tiene constructor, así que usa el de Animal, y por eso funciona new Dog('Rex'). Una clase hija solo puede extender un padre; PHP no tiene herencia múltiple de clases.

Llamar al método del padre con parent::

Sobrescribir sustituye por completo el método del padre. Para ampliarlo en lugar de sustituirlo, llama a parent::method() desde la hija y construye sobre su resultado:

Lo mismo funciona con los constructores mediante parent::__construct(...), que explica la página del constructor, incluido lo que pasa cuando lo olvidas.

protected vs private en las clases hijas

Un miembro protected está oculto para el código de fuera pero es visible para todas las clases de la familia. Un miembro private solo es visible en la clase que lo declara, así que una clase hija no puede verlo en absoluto:

isset($this->pin) es falso en la hija porque la hija no tiene acceso al $pin privado del padre, mientras que el propio método del padre, hasPin(), sí lo lee. Usa protected para lo que las subclases deben aprovechar, y private para los detalles que quieres poder cambiar libremente.

Polimorfismo e instanceof

El código escrito para el tipo padre funciona con cada hija. Cada objeto ejecuta su propia versión de un método sobrescrito, así que un solo bucle los maneja a todos. instanceof comprueba si un objeto es de una clase o de cualquiera de sus hijas:

Cuando el padre nunca deba usarse por sí solo (un Shape genérico con área 0 tiene poco sentido), hazlo clase abstracta y declara area() como abstracto.

Reglas de la sobrescritura: las firmas deben seguir siendo compatibles

Un método que sobrescribe debe aceptar al menos lo que aceptaba el padre y devolver algo que puedan usar quienes llamaban al padre. Puedes añadir un parámetro opcional, ampliar el tipo de un parámetro o restringir el tipo de retorno; no puedes añadir un parámetro obligatorio ni hacer privado un método público.

Cambia string $sep = ',' por un string $sep obligatorio y PHP se niega a compilar la clase con un error fatal ("Declaration of CsvExporter::export(array rows,stringrows, string sep): string must be compatible with Exporter::export(array $rows): string").

Clases y métodos final

final detiene la herencia en ese punto. Un método final no se puede sobrescribir, y una final class no se puede extender. Las dos cosas se comprueban al compilar el archivo, así que el script ni siquiera empieza:

<?php
class Payment
{
    final public function charge(int $cents): string
    {
        return "charged $cents";
    }
}

class FreePayment extends Payment
{
    public function charge(int $cents): string
    {
        return 'free';
    }
}
PHP Fatal error:  Cannot override final method Payment::charge() in /home/index.php on line 12

Para una clase final, el mensaje es Class B cannot extend final class A. Marca un método como final cuando el padre dependa de que se comporte exactamente de una forma, por ejemplo un método que comprueba los permisos antes de hacer nada más.

La trampa de los métodos privados

Un método privado no se hereda, así que un método hijo con el mismo nombre no lo sobrescribe. El código del padre sigue llamando a su propia versión privada, lo que sorprende a quien espera que se ejecute el método de la hija:

greet() sigue imprimiendo Hello: el $this->word() del padre se resuelve con el método privado del padre. Cambia private por protected en Greeter y vuelve a ejecutarlo; ahora el método de la hija es una sobrescritura real y greet() dice Bonjour.

Preguntas frecuentes

¿Cómo funciona extends en PHP?

class Dog extends Animal hace de Dog una hija de Animal. Un objeto Dog tiene todas las propiedades y métodos públicos y protegidos de Animal, puede añadir los suyos y puede sustituir (sobrescribir) los métodos heredados declarando un método con el mismo nombre.

¿Cómo llamo al método del padre en PHP?

Usa parent::methodName() dentro del método de la hija, por ejemplo return parent::describe() . ' and more';. Para el constructor es parent::__construct(...).

¿PHP admite herencia múltiple?

No. Una clase solo puede extender una clase padre. Para compartir comportamiento de varias fuentes, implementa varias interfaces (class A implements B, C) y usa traits (use Loggable, Timestamps;).

¿Qué significa final en PHP?

Un método final no se puede sobrescribir en una clase hija, y una final class no se puede extender en absoluto. Romper cualquiera de las dos reglas es un error fatal al compilar la clase, por ejemplo Cannot override final method A::f().

¿Una clase hija puede acceder a una propiedad privada de su padre en PHP?

No. Un miembro private pertenece solo a la clase que lo declara, así que en la hija $this->pin es una propiedad no definida (un warning y luego null) y un método hijo con el mismo nombre no sobrescribe uno privado. Declara el miembro protected cuando las clases hijas lo necesiten.

Ilustración de los lenguajes de programación de Coddy

Aprende a programar con Coddy

COMENZAR