Le classi astratte



Dalle lezioni precedenti, abbiamo imparato che l'ereditarietà e l'estensione sono due concetti di fondamentale importanza nella programmazione orientata agli oggetti, o meglio ancora, il vero nucleo dello stesso paradigma. Abbiamo visto inoltre che è possibile estendere le superclassi con classi che ereditano le loro funzionalità condivise, con funzionalità del tutto nuove e personalizzate. Tuttavia non esiste ancora, a questo punto della nostra guida, un modo per definire delle regole precise in fase di estensione: le sottoclassi avranno l'implementazione decisa dal creatore delle stesse.

Tralasciando i vantaggi elencati nelle precedenti lezioni, possiamo affermare che questa totale libertà può costituire gli stessi svantaggi del codice procedurale, dato che di conseguenza si potrebbero ottenere classi con namespaces, funzionalità e stili completamente differenti. Assumiamo il caso in cui abbiamo una superclasse chiamata Base sviluppata da un team "A", che viene estesa dalle sottoclassi More1 e More2 create rispettivamente dai team "B" e "C". La struttura risultante è dipendente dalle preferenze e dagli stili di ogni gruppo:

class Base {
        public function getName($who) { // ... }
        public function getAge($who) { // ... }
}

classe More1 extends Base {
        public function getName($who, $dflt) { // ... }
        public function getAge($who, $dflt, $ext) { // ... }
}

classe More2 extends Base {
        protected function get_name($who) { // ... }
        protected function get_age($who, $name) { // ... }
}

Come possiamo notare, ogni team può decidere in modo arbitrario la struttura dei metodi e della classe stessa, le regole per il namespacing e gli indicatori di visibilità. In questo modo, in mancanza di un particolare accordo tra i gruppi, sarà molto difficile (e confusionario) fare coesistere le differenti API nella stessa applicazione.

A questo scopo nascono le classi astratte. Si tratta di classi "wrapper" o "skeleton" che non è possibile istanziare in alcun modo, il cui scopo è quello di contenere le indicazioni sull'implementazione desiderata. Una classe astratta dunque, contiene gli elementi fondamentali da condividere con le sottoclassi, ma non solo. Nelle classi astratte è possibile dichiarare i metodi come astratti, facendoli precedere dalla keyword abstract, e tralasciare il loro corpo.

Se una classe estende una classe astratta, deve ridefinire tutti i metodi dichiarati come astratti con proprie implementazioni, assumendo così una struttura comune.

Caratteristiche delle classi astratte

Vediamo ora nel dettaglio le caratteristiche di una classe astratta. Sintatticamente, per dichiarare una classe come astratta, la parola chiave class ed il nome della stessa devono essere precedute dalla keyword abstract, per il resto è tutto identico alle classi normali:

abstract class Base {
        // implementazione...
}

In questo modo sappiamo che non sarà possibile creare istanze della classe Base, altrimenti otterremo un Fatal Error:

// istanziamo una classe astratta
$abs = new Base();

Fatal error: Cannot instantiate abstract class Base in [...]

Per capire perchè ciò accade, occorre ripassare la definizione delle istanze: esse sono rappresentazioni concrete delle classi. Le classi astratte, in quanto tali, non possono ovviamente produrre oggetti, ma devono essere a loro volta estese da classi normali che si occupano della produzione delle istanze finali.

Ora possiamo passare alla dichiarazione dei metodi astratti, che a loro volta, sono preceduti dalla keyword abstract:

abstract class Base {
        abstract public function getName($who);
        abstract public function getAge($who);
}

Come possiamo notare, i metodi astratti non hanno un corpo: sarà compito delle classi eredi fornire un'implementazione per questi ultimi. Ovviamente, deve essere rispettato lo stesso namespace, gli stessi argomenti e lo stesso indicatore di visibilità.

Nota bene: se una classe contiene anche un solo metodo dichiarato come abstract, essa deve essere obbligatoriamente dichiarata come abstract, altrimenti verrà generato un Fatal Error (le classi normali non possono contenere metodi astratti):

Polimorfismo

Tramite le classi astratte, possiamo attuare il conetto che prende il nome di polimorfismo. In pratica le rispettive sottoclassi di una classe astratta, devono conformarsi con delle regole precise definite da quest'ultima, dunque, pur essendo classi di tipi differenti, si comportano ed "assumono" la forma comune.

Conclusione

Dopo avere analizzato le teorie che stanno alla base delle classi astratte e la loro importanza nella OOP, è ora di passare ad osservarle in maniera pratica con la prossima lezione, dove avremo una API vera e propria che condivide le stesse regole sintattiche e logiche.

Ultimi articoli PHP

Sessioni PHP: cosa sono, come si usano

Dalla configurazione di PHP, alla gestione delle sessioni in un...

Continuous Integration: automatizziamo i client con Phing

Continuous Integration: automatizziamo i client con Phing. Esempi...

Archiviazione delle applicazioni PHP con Phar

Come incorporare intere applicazioni PHP all'interno di un singolo...

I traits in PHP 5.4

Cosa sono, a cosa servono e come si unsano i traits, la novità per...

PHP 5.4: il web server integrato

Impara ad usare il web server integrato nella versione 5.4 di PHP:...

Altri articoli

Guide PHP

Guida Yii Framework

Come creare applicazioni Web in modo semplice e veloce con il...

Guida Applicazioni Facebook con PHP

Come realizzare un'applicazione per Facebook. Dalle basi della...

Guida PHP con Windows e IIS

Installare ambienti per lo sviluppo e la produzione di applicazioni...

Altre guide

Newsletter @PHP

Ogni lunedì, direttamente nella tua e-mail: script, articoli, guide e tutorial su PHP, MySQL e Apache.

Iscriviti alla newsletter

Altre newsletter

Corsi in aula

Corso PHP per Webmaster

11 Giugno 2012 a Milano
Disponibilità: 7 Posti

Corso Google AdWords Base

25 Giugno 2012 a Milano
Disponibilità: 7 Posti

Corso Google AdWords Base

05 Giugno 2012 a Roma
Disponibilità: 7 Posti