Comprendere la programmazione orientata agli oggetti in PHP: il concetto di classi astratte
Scopri le classi astratte in PHP: come dichiararle con abstract, implementare i metodi astratti nelle classi figlie e quando preferirle alle interfacce.
In PHP, la programmazione orientata agli oggetti (OOP) ti aiuta a scrivere codice pulito, ordinato e manutenibile. Un elemento fondamentale dell'OOP è la classe astratta: una classe che definisce un contratto condiviso per una famiglia di classi correlate, senza poter essere usata da sola.
Questo capitolo spiega che cos'è una classe astratta, come dichiararne una con la parola chiave abstract, come i metodi abstract obbligano le classi figlie a fornire un'implementazione e quando conviene scegliere una classe astratta al posto di un'interfaccia.
Che cos'è una classe astratta?
Una classe astratta è un modello per creare oggetti, ma non può essere istanziata direttamente. Serve invece come base da cui altre classi ereditano proprietà e metodi comuni. Può combinare due tipi di metodi:
- Metodi concreti: metodi completamente implementati, che ogni classe figlia eredita così come sono.
- Metodi astratti: metodi che dichiarano solo una firma (nome, visibilità e parametri) senza corpo. Ogni classe figlia non astratta deve implementarli.
Questa combinazione permette alla classe padre di imporre che cosa deve esistere, lasciando a ciascuna classe figlia il come funziona: è il fondamento del polimorfismo in PHP. Se l'ereditarietà è nuova per te, leggi prima Ereditarietà in PHP.
Vantaggi delle classi astratte
- Incapsulamento: le classi astratte possono incapsulare proprietà e metodi comuni, rendendo più semplice mantenere la coerenza tra classi correlate.
- Riutilizzo del codice: il meccanismo di ereditarietà dell'OOP consente agli sviluppatori di creare nuove classi estendendo quelle esistenti, comprese le classi astratte. Questo può ridurre la quantità di codice da scrivere e rendere lo sviluppo più efficiente.
- Progettazione migliore: usando le classi astratte, gli sviluppatori possono creare una gerarchia di classi chiara, che rende più facile capire le relazioni tra le diverse parti del codice.
- Flessibilità: definendo una classe astratta, gli sviluppatori possono specificare quali proprietà e metodi devono essere inclusi in una classe derivata, lasciandone però i dettagli di implementazione alla classe derivata stessa. Questo offre un certo grado di flessibilità e permette di creare classi personalizzate per scopi specifici.
Come definire una classe astratta in PHP
Per creare una classe astratta in PHP, inserisci la parola chiave abstract prima della dichiarazione class. Contrassegna con abstract anche ogni metodo che le classi figlie devono implementare: un metodo astratto termina con un punto e virgola e non ha un corpo { }.
Esempio di classe astratta in PHP
abstract class Shape {
// Concrete method: shared by every child as-is.
public function describe(): string {
return "A shape with area " . $this->getArea();
}
// Abstract method: each child must implement it.
abstract public function getArea(): float;
}Qui Shape è dichiarata abstract, quindi non può essere trasformata direttamente in un oggetto. Fornisce a tutte le classi figlie un metodo describe() già pronto, mentre getArea() resta astratto: ogni sottoclasse concreta deve fornire la propria versione.
Le classi astratte non possono essere istanziate
Se provi a creare un oggetto da una classe astratta, PHP genera un errore fatale:
$shape = new Shape(); // Fatal error: Cannot instantiate abstract class ShapeÈ proprio questo il punto: una classe astratta è incompleta finché una classe figlia non ne completa i metodi astratti. Anche la visibilità di un metodo astratto (public, protected) viene fatta rispettare: la classe figlia non può renderla più restrittiva. Consulta Modificatori di accesso in PHP per le regole sulla visibilità.
Estendere una classe astratta in PHP
Per estendere una classe astratta, usa la parola chiave extends e implementa ogni metodo astratto. Una classe figlia può anche aggiungere un proprio costruttore e ulteriori membri.
Estendere una classe astratta in PHP
class Rectangle extends Shape {
public function __construct(
protected float $width,
protected float $height
) {}
public function getArea(): float {
return $this->width * $this->height;
}
}
class Circle extends Shape {
public function __construct(protected float $radius) {}
public function getArea(): float {
return M_PI * $this->radius ** 2;
}
}Sia Rectangle sia Circle estendono Shape e forniscono il proprio getArea(). Ereditano il metodo concreto describe() senza doverlo riscrivere.
Cosa succede se una classe figlia dimentica un metodo astratto?
Se una classe figlia non astratta non implementa tutti i metodi astratti, PHP rifiuta di compilare il file:
class Triangle extends Shape {} // Fatal error: Class Triangle contains 1
// abstract method and must therefore be
// declared abstract or implement getArea()Il compilatore rileva il metodo mancante prima ancora che il tuo codice venga eseguito: questa garanzia è ciò che rende le classi astratte utili per imporre un contratto.
Usare una classe astratta
Non istanzi mai la classe astratta stessa: istanzi una classe figlia concreta e ne chiami i metodi. Poiché ogni classe figlia rispetta lo stesso contratto, puoi trattarle in modo uniforme (polimorfismo):
Esempio di utilizzo di una classe astratta in PHP
$shapes = [
new Rectangle(10, 5),
new Circle(3),
];
foreach ($shapes as $shape) {
echo round($shape->getArea(), 2), "\n";
}
// Output:
// 50
// 28.27Ogni oggetto risolve getArea() nella propria implementazione, mentre describe() (ereditato da Shape) funziona allo stesso modo per tutti.
Classe astratta e interfaccia a confronto
Le classi astratte e le interfacce definiscono entrambe un contratto, ma presentano differenze:
| Caratteristica | Classe astratta | Interfaccia |
|---|---|---|
| Può contenere metodi implementati | Sì | No: i metodi sono solo firme (senza corpo) |
| Può contenere proprietà / stato | Sì | Solo costanti |
| Quante può averne una classe | Una (ereditarietà singola) | Molte (implements A, B) |
| Quando usarla | Le classi figlie condividono codice e un contratto | Serve solo un contratto, magari tra classi non correlate |
Scegli una classe astratta quando classi correlate condividono un'implementazione reale; scegli un'interfaccia quando vuoi solo garantire l'esistenza di un insieme di metodi. Per approfondire, consulta Interfacce in PHP e Classi e oggetti in PHP.
Conclusione
Le classi astratte offrono un modo per imporre coerenza e struttura nel tuo codice PHP e portano numerosi vantaggi, come incapsulamento, riutilizzo del codice, progettazione migliore e flessibilità. Che tu sia uno sviluppatore PHP esperto o che tu abbia appena iniziato, comprendere il concetto di classi astratte è un passo importante per padroneggiare l'OOP in PHP.