Progettare una classe
Nella progettazione di una classe, come regola guida, si dovrebbe continuare a pensare come nel mondo reale. Questo se, da una parte, sembra essere molto ovvio, dall'altra, risulta abbastanza nebuloso. Per fortuna è possibile elencare una serie di regolette, seguendo le quali la scrittura del codice risulta particolarmente leggibile:
Se ci si chiede perchè debba essere necessario utilizzare delle apposite funzioni per leggere e scrivere le variabili, una possibile risposta potrebbe essere che la pratica dell'OOP impone che gli oggetti debbano essere autosufficienti. Le altre parti del programma devono essere in grado di lavorare con gli oggetti utilizzando semplici chiamate di funzione. Per esempio, si immagini di programmare un gioco di strategia in cui i giocatori possono controllare più città , e ogni città possiede delle scorte di cibo proporzionali al numero di operai presenti. Ora, se il giocatore cambia il numero degli operai di una certa città fissandolo a 800, la modifica può essere fatta con un codice simile a questo:
$City->_Workers = 800;
E se si volesse tenere conto anche della disponibilità di cibo in funzione dell'attività degli operai si dovrebbe usare il codice seguente:
$City->_Workers = 800;
$City->_FoodSurplus = WORKER_SPEED * 800;
A questo punto, cosa succede se un paio di settimane più tardi si decide che le persone possono migliorare le loro città costruendo aziende agricole e impianti di trasformazione che aumentano la disponibilità di cibo? Si dovrebbe andare alla ricerca su tutto il codice per modificare la variabile _FoodSurplus, ed assicurarsi che abbia il valore corretto. Ma in seguito, se si desidera apportare ulteriori modifiche, è necessario ripetere ogni volta questa procedura. Sarebbe il codice chiamante a dover avere la conoscenza esplicita di come gestire le modifiche relative agli operai della città .
Questo non è il modo di operare della OOP. Nel mondo OOP è l'oggetto città che deve gestire tutti i calcoli necessari, lasciando che il codice chiamante possa scrivere semplicemente:
City->SetWorkers(800);
La funzione SetWorkers() deve contenere tutto il necessario per operare tutti gli altri cambiamenti conseguenti. Il punto chiave è che il codice chiamante non deve aver bisogno di sapere nulla su cosa comporta il cambiamento del parametro, le eventuali modifiche devono essere fatte a livello di classe, e la funzione SetWorkers() fa proprio questo.
Ereditarietà di base
Per poter creare una classe derivata, è necessario introdurre la parola chiave extends che consente di passare in eredità ad una nuova classe le caratteristiche di una classe di partenza, in questo modo:
class cane {
public function abbaia() {
print "Bau!\n";
}
}
class barboncino extends cane {
// ancora niente di nuovo,
// questa classe è un clone della precedente
}
Funzioni sostituzione
PHP permette di ridefinire le funzioni nelle sottoclassi, il che significa che possiamo fare in modo che la classe barboncino abbia una propria versione della funzione abbaia(). Questo meccanismo, chiamato sostituzione o override viene realizzato semplicemente ridefinendo la funzione all'interno della classe figlia. Nel nostro caso la classe barboncino diviene:
class barboncino extends cane {
public function abbaia() {
print "Yip!\n";
}
}
Oggetti
Le classi sono, però, delle semplici definizioni, per lavorare concretamente occorre un esemplare reale derivato dal nostro modello. Naturalmente non possiamo creare animali vivi negli script PHP, ma la cosa migliore che possiamo fare è la creazione di un esemplare (in inglese instance) della nostra classe.
Nella parte introduttiva avevamo citato Fuffy, barboncino della classe Cane, vediamo come ricrearlo con le possibilità offerte dall'OOP di PHP:
<?php
class cane {
public function abbaia() {
print "Bau!\n";
}
}
class barboncino extends cane {
/* public function abbaia() {
print "Yip!\n";
} */
}
$fuffy = new barboncino;
$fuffy->abbaia();
?>
La parola chiave new ha consentito la creazione di un'istanza della classe barboncino. Noi lavoreremo sempre sulle istanze, cioè sugli esemplari, e non sulle classi che sono solo dei modelli. Le classi sono come dei timbri che consentono la replica di tante impronte reali.
Se eseguiamo lo script si vedrà sul display che Fuffy abbaia emettendo il verso "Bau!".
Se proviamo ad eliminare i commenti presenti nella funzione abbaia() della classe barboncino, e rieseguiamo lo script, adesso Fuffy abbaierà emettendo il verso "Yip!".
Un piccolo difetto è quasi sempre l'inizio di uno grande.
Cavalcanti