Una classe astratta PHP si dichiara con abstract class Name e non può essere creata con new. È una base per altre classi: può avere proprietà, un costruttore e metodi completi, più metodi abstract senza corpo, che ogni classe figlia deve implementare.
describe() è scritto una volta in Shape e chiama area(), che ogni figlia fornisce. La classe astratta garantisce che il metodo esista, quindi describe() può contarci.
Non puoi creare una classe astratta con new
Una classe astratta è incompleta di proposito: Shape::area() non ha corpo, quindi un semplice oggetto Shape non avrebbe nulla da eseguire. PHP si rifiuta di crearne uno e lancia un Error:
Metodi astratti: le regole
Un metodo astratto ha una firma e un punto e virgola al posto del corpo. Ogni figlia deve implementarlo con una firma compatibile e una visibilità uguale o più ampia: un metodo abstract protected può diventare protected o public nella figlia, mai private. Una classe con anche un solo metodo astratto deve essere a sua volta dichiarata astratta.
Una figlia che salta un metodo astratto ferma lo script prima che ne venga eseguita qualsiasi parte, a meno che la figlia non sia anch'essa dichiarata astratta e lasci il metodo alle proprie figlie:
PHP Fatal error: Class Square contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Shape::area) in /home/index.php on line 3
Il pattern template method
Il motivo più comune per scrivere una classe astratta: una sequenza fissa di passaggi in cui alcuni passaggi cambiano. La classe base possiede la sequenza in un metodo final, e le figlie completano i passaggi. Qui lo stesso report viene prodotto come testo semplice e come tabella HTML:
Eseguilo e la scheda Page mostra la tabella HTML sopra la versione in testo semplice. open() e close() hanno un corpo di default, quindi solo HtmlReport si preoccupa di sovrascriverli; row() è astratto perché non esiste un default sensato. Rendere render() final impedisce a una figlia di cambiare l'ordine dei passaggi.
Una classe astratta può implementare un'interfaccia
Una classe astratta può dichiarare implements e lasciare alcuni metodi dell'interfaccia alle sue figlie. È il modo standard di abbinare un'interfaccia (il tipo) a una classe base (il codice condiviso):
Il codice usa come type hint l'interfaccia Cache, quindi una classe che non può estendere BaseCache (perché estende già qualcos'altro) può comunque implementare direttamente Cache.
Quando usare una classe astratta, e quando no
Usa una classe astratta quando le classi di una famiglia condividono codice reale: proprietà, un costruttore, metodi uguali per tutte. Se la base contenesse solo metodi astratti, sarebbe un'interfaccia travestita, e un'interfaccia è la scelta migliore perché una classe può implementare molte interfacce ma estendere una sola classe. Se vuoi solo condividere qualche metodo di supporto tra classi non correlate, usa un trait invece di forzarle sotto un unico padre.
Un test rapido prima di scrivere abstract class: ogni figlia sarebbe davvero un tipo della base (Circle è uno Shape)? Se la risposta onesta è "sa fare questo" invece di "è uno di questi", scrivi un'interfaccia.
Domande frequenti
Cos'è una classe astratta in PHP?
Una classe dichiarata con abstract class Name che non può essere creata con new. È una base per altre classi: può contenere proprietà, un costruttore e metodi normali, e può dichiarare metodi abstract che ogni classe figlia deve implementare.
Cos'è un metodo astratto in PHP?
Un metodo dichiarato con abstract e senza corpo: abstract protected function render(array $rows): string;. Una classe che ne contiene uno deve essere a sua volta dichiarata abstract, e ogni classe figlia non astratta deve definire un metodo con una firma compatibile.
Una classe astratta può avere un costruttore in PHP?
Sì. Non puoi chiamare new sulla classe astratta, ma il suo costruttore viene eseguito quando si crea una classe figlia, automaticamente (se la figlia non ha un costruttore) oppure tramite parent::__construct(...).
Si può istanziare una classe astratta in PHP?
No. new Shape() su una classe astratta lancia un Error: Cannot instantiate abstract class Shape. Crea invece un oggetto di una classe figlia concreta, per esempio new Circle(2).
Quando usare una classe astratta in PHP?
Quando più classi correlate condividono codice reale (proprietà, un costruttore, metodi comuni) e differiscono in pochi passaggi. Metti il codice condiviso nella classe astratta e dichiara astratti i passaggi che cambiano. Se non c'è codice condiviso e ti serve solo un contratto, usa un'interfaccia.