Ereditarietà e polimorfismo in PHP: extends, abstract, final
Override dei metodi, chiamata parent::, classi e metodi final
Hai due classi quasi identiche: Cane e Gatto, entrambe con nome, età e un metodo descrivi(). Copiare il codice due volte è uno spreco, ed è anche un rischio: correggerlo in un posto e dimenticarsene nell'altro è un classico. L'ereditarietà risolve esattamente questo: una classe eredita da un'altra, riusando ciò che hanno in comune.
Sei dipendete di un'azienda: il contratto standard (la classe padre) definisce ferie, orario, benefit di base. Un contratto per manager (la classe figlia) eredita tutto quello che è presente nel contratto standard, e aggiunge solo le clausole specifiche del ruolo, senza riscrivere da capo l'intero documento.
1. extends: ereditare, e sovrascrivere quando serve
Quando una classe estende un'altra, eredita tutti i metodi, le proprietà e le costanti public e protected, non quelli private, che restano esclusivi della classe che li ha dichiarati.
class Animale {
public function __construct(protected string $nome) {}
public function descrivi(): string {
return "{$this->nome} e' un animale";
}
}
class Cane extends Animale {
// eredita $nome e descrivi() automaticamente
public function abbaia(): string {
return "{$this->nome} fa Bau!";
}
}
Se la sottoclasse ridefinisce un metodo con lo stesso nome, lo sovrascrive (override), a meno di richiamare esplicitamente la versione del genitore con parent::.
class Cane extends Animale {
public function descrivi(): string {
return parent::descrivi() . ", nello specifico un cane";
}
}
(new Cane('Fido'))->descrivi();
// "Fido e' un animale, nello specifico un cane"
2. abstract: un progetto che obbliga a completarlo
Una classe abstract non può essere istanziata direttamente con new, serve solo come base da estendere. Un metodo astratto (dichiarato senza corpo) obbliga ogni sottoclasse concreta a implementarlo, o PHP genera un errore.
abstract class FormaGeometrica {
abstract public function area(): float;
public function descrivi(): string {
return "Area: " . $this->area();
}
}
class Quadrato extends FormaGeometrica {
public function __construct(private float $lato) {}
public function area(): float {
return $this->lato ** 2;
}
}
new FormaGeometrica(); // Fatal error: Cannot instantiate abstract class
3. final: bloccare l'ereditarietà o l'override
final ha due usi. Su un metodo, impedisce alle sottoclassi di sovrascriverlo: utile per logica critica che non deve mai essere alterata. Su una classe intera, impedisce che venga estesa affatto.
class Pagamento {
final public function elabora(float $importo): void {
$this->valida($importo);
$this->addebita($importo);
}
protected function valida(float $importo): void { /* ... */ }
protected function addebita(float $importo): void { /* ... */ }
}
final class Configurazione {
// nessuna classe potra' mai estendere Configurazione
}
Un uso comune: final private function __construct() per «disabilitare» il costruttore normale quando la classe deve essere creata solo tramite metodi statici di fabbrica (static factory method).
In sintesi
Il polimorfismo, l'idea che oggetti di classi diverse rispondano allo stesso metodo in modo diverso, nasce proprio da qui: Cane e Gatto possono condividere descrivi() per nome, ma ciascuno lo esegue a modo suo, senza che il codice che li usa debba nemmeno saperlo.
Commenti (0)
Registrati per commentare, fare domande e proporre l'argomento della prossima pillola (oppure accedi se hai già un account).
Nessun commento. Sii il primo a scrivere qualcosa.