W3docs

Ereditarietà OOP in PHP

Scopri l'ereditarietà OOP in PHP: sintassi extends, override dei metodi, parent::, costruttori e la parola chiave final con esempi pratici.

L'ereditarietà consente a una classe di riutilizzare le proprietà e i metodi di un'altra, permettendo di modellare relazioni "è-un" (una Car è un Vehicle) senza copiare codice. In PHP viene implementata con la parola chiave extends. Questo capitolo tratta la sintassi, il funzionamento dell'override dei metodi e della parola chiave parent, l'ereditarietà dei costruttori, il ruolo della visibilità e della parola chiave final, oltre a un esempio completo eseguibile con cui sperimentare.

Se sei nuovo alle classi, inizia con Classi e Oggetti PHP, poi torna qui.

Cos'è l'Ereditarietà?

L'ereditarietà è la capacità di definire una nuova classe (la classe figlia, sottoclasse o classe derivata) basandosi su una esistente (la classe genitore, superclasse o classe base). La classe figlia acquisisce automaticamente i membri public e protected del genitore e può:

  • riutilizzarli così come sono,
  • sovrascriverli con una propria implementazione, oppure
  • aggiungere nuove proprietà e metodi.

PHP supporta esclusivamente l'ereditarietà singola: una classe può estendere esattamente un genitore. Tuttavia, è possibile costruire una catenaHatchback extends Car extends Vehicle — e una classe può anche implementare molte interfacce quando si ha bisogno di comportamenti provenienti da più sorgenti.

Vantaggi dell'Ereditarietà

  • Riutilizzabilità — la logica condivisa vive nel genitore, quindi la si scrive una sola volta.
  • Manutenibilità — una correzione nel genitore si propaga a tutte le sottoclassi; meno duplicazione significa meno posti in cui i bug possono nascondersi.
  • Polimorfismo — il codice che si aspetta un Vehicle funziona con qualsiasi sottoclasse, permettendo di scambiare liberamente le implementazioni.
  • Modellazione chiara — la gerarchia delle classi documenta le relazioni "è-un" nel proprio dominio.

Sintassi dell'Ereditarietà OOP in PHP

Per creare una sottoclasse, si usa extends seguito dal nome della classe genitore:

class ChildClass extends ParentClass {
    // child-specific properties and methods
}

ChildClass ora possiede tutti i membri public e protected di ParentClass. Si noti che i membri private del genitore non sono accessibili dalla classe figlia — usa protected quando vuoi che le sottoclassi possano accedere a un membro, ma che rimanga nascosto al codice esterno. Consulta Modificatori di Accesso PHP per le regole complete sulla visibilità.

Sovrascrittura dei Metodi del Genitore

Una sottoclasse sovrascrive un metodo del genitore dichiarando un metodo con lo stesso nome. La versione della classe figlia sostituisce quella del genitore per gli oggetti di quella sottoclasse:

class ParentClass {
    public function displayMessage() {
        echo "Hello from ParentClass";
    }
}

class ChildClass extends ParentClass {
    public function displayMessage() {
        echo "Hello from ChildClass";
    }
}

Chiamare il metodo genitore con parent::

Sovrascrivere non significa necessariamente sostituire — spesso si vuole estendere il comportamento del genitore. Usa parent:: per chiamare prima la versione del genitore, poi aggiungere il proprio comportamento:

class ChildClass extends ParentClass {
    public function displayMessage() {
        parent::displayMessage(); // runs the parent's logic
        echo " — and hello from ChildClass";
    }
}

Aggiungere l'attributo #[\Override] (PHP 8.3+) sopra un metodo indica a PHP di generare un errore se il metodo non sovrascrive effettivamente un metodo del genitore — un modo economico per individuare errori di battitura nei nomi dei metodi.

Ereditarietà ed Estensione dei Costruttori

Se una classe figlia non definisce un proprio costruttore, il costruttore del genitore viene ereditato ed eseguito automaticamente. Se la classe figlia definisce il proprio costruttore, il costruttore del genitore non viene chiamato automaticamente — è necessario chiamarlo esplicitamente con parent::__construct(...):

class Vehicle {
    public function __construct(public string $make) {}
}

class Car extends Vehicle {
    public function __construct(string $make, public string $fuelType) {
        parent::__construct($make); // initialise the inherited part
    }
}

Per ulteriori informazioni sui costruttori, consulta Costruttore PHP.

Impedire la Sovrascrittura con final

Contrassegna un metodo come final per impedire alle sottoclassi di sovrascriverlo, oppure contrassegna un'intera classe come final per impedire che venga estesa del tutto:

class PaymentBase {
    final public function transactionId(): string {
        return 'TX-' . uniqid();
    }
}

Questo è utile per la logica che deve comportarsi in modo identico ovunque. Consulta Parola chiave final in PHP per i dettagli. Quando il genitore deve definire la firma di un metodo ma forzare ogni classe figlia a fornire il corpo, usa invece una classe astratta.

Esempio di Ereditarietà OOP in PHP

Ecco un programma completo ed eseguibile. Una classe base Vehicle contiene i dati comuni, e una sottoclasse Car aggiunge una proprietà fuelType ed estende displayDetails() tramite parent:::

<?php

class Vehicle
{
    public function __construct(
        protected string $make,
        protected string $model,
        protected int $year
    ) {}

    public function displayDetails(): void
    {
        echo "Make: {$this->make}\n";
        echo "Model: {$this->model}\n";
        echo "Year: {$this->year}\n";
    }
}

class Car extends Vehicle
{
    public function __construct(
        string $make,
        string $model,
        int $year,
        protected string $fuelType
    ) {
        parent::__construct($make, $model, $year);
    }

    public function displayDetails(): void
    {
        parent::displayDetails();           // reuse the parent's output
        echo "Fuel Type: {$this->fuelType}\n"; // then add our own
    }
}

$car = new Car('Toyota', 'Corolla', 2023, 'Hybrid');
$car->displayDetails();

Output:

Make: Toyota
Model: Corolla
Year: 2023
Fuel Type: Hybrid

Car eredita make, model e year (dichiarati protected, in modo che la sottoclasse possa utilizzarli), riutilizza il displayDetails() del genitore tramite parent::, e aggiunge la propria riga per fuelType.

Problemi Comuni

  • private non viene ereditato. Una proprietà private del genitore è invisibile alla classe figlia. Usa protected se le sottoclassi ne hanno bisogno.
  • I costruttori non vengono concatenati automaticamente quando la classe figlia ne definisce uno proprio — chiama sempre parent::__construct() manualmente.
  • PHP non supporta l'ereditarietà multipla. Una classe estende un solo genitore; usa interfacce o trait per condividere comportamenti da più sorgenti.
  • La sovrascrittura ignora silenziosamente gli errori di battitura prima di PHP 8.3 — un nome di metodo scritto in modo errato crea semplicemente un nuovo metodo invece di sovrascriverlo. Aggiungi #[\Override] per sicurezza.

Conclusione

L'ereditarietà consente a una sottoclasse di riutilizzare, sovrascrivere ed estendere i membri di una classe genitore tramite la parola chiave extends, con parent:: che fornisce accesso all'implementazione originale. Combinata con i modificatori di visibilità, i costruttori e final, costituisce la base del riutilizzo del codice e del polimorfismo nella OOP PHP. Successivamente, esplora le classi astratte e le interfacce per progettare gerarchie di classi più pulite.

Pratica

Pratica
Nell'ereditarietà PHP, quali delle seguenti affermazioni sono vere?
Nell'ereditarietà PHP, quali delle seguenti affermazioni sono vere?
Was this page helpful?