Costruttori
Se ripensiamo all'esempio in cui ogni cane aveva un oggetto dogtag, ci troviamo di fronte ad un codice come questo:
$poppy = new poodle;
$poppy->Name = "Poppy";
$poppy->DogTag = new dogtag;
$poppy->DogTag->Words = "My name is Poppy. If you find me, please call 555-1234";
Se riflettiamo un poco, questo codice è abbastanza rozzo. Immaginiamo di avere altri oggetti dentro l'oggetto poodle, dovremmo creare ogni volta sia l'oggetto poodle sia tutti gli oggetti ad esso associati.
Per fortuna c'è un modo per evitare tutto questo, l'uso del costruttore. Il costruttore è una funzione di classe speciale che viene chiamato da PHP ogni volta che si crea un'istanza di una data classe. Diamo un'occhiata a questo script:
<?php
class dogtag {
public $Words;
}
class dog {
public $Name;
public $DogTag;
public function bark() {
print "Woof!\n";
}
public function __construct($DogName) {
print "Creating $DogName\n";
$this->Name = $DogName;
$this->DogTag = new dogtag;
$this->DogTag->Words = "My name is $DogName. If you find me, please call 555-1234";
}
}
class poodle extends dog {
public function bark() {
print "Yip!\n";
}
}
$poppy = new poodle("Poppy");
print $poppy->DogTag->Words . "\n";
?>
E' uno script piuttosto lungo, ma è solo una combinazione di codice che abbiamo già visto fino ad ora, con la nuova aggiunta che vengono utilizzati i costruttori. Da notare la funzione __construct() nella classe dog, che usa una variabile, questo è il nostro costruttore. Ogni volta che si crea un'istanza di un oggetto poodle, PHP chiama il costruttore in questione.
Ci sono tre cose importanti da notare:
parent::__construct()
Diamo un'occhiata al codice seguente:
class poodle extends dog {
public function bark() {
print "Yip!\n";
}
public function __construct($DogName) {
print "Creating a poodle\n";
}
}
Se si sostituisce la definizione originale di poodle con quest'ultima e si prova ad eseguire nuovamente lo script, si otterrà l'errore "Trying to get property of non-object" in corrispondenza della riga $poppy->DogTag->Words. La ragione di questo è che DogTag è già definito come un'istanza dell'oggetto dogtag nel costruttore della classe dog, e, poichè PHP chiama sempre un solo costruttore, il costruttore della classe dog non viene chiamato perché PHP trova prima il costruttore poodle.
Il fatto è che PHP chiama sempre il costruttore "più vicino", e solo se non c'è il costruttore del figlio si chiamerà il costruttore del genitore e non il costruttore del nonno, e quindi occorrerà chiamare esplicitamente il costruttore del genitore. Possiamo realizzare questo con la funzione speciale parent::__construct(). La parte "parent" significa "ottenere il padre di questo oggetto, e usarlo", mentre la parte "__construct()" significa naturalmente "chiamare la funzione construct". Così tutta la linea significa "prendere il genitore di questo oggetto e poi chiamare il suo costruttore".
Come si può vedere, la chiamata a parent::__construct() è una normale chiamata di funzione, e il costruttore dog ha bisogno del nome del cane come suo parametro. Quindi, per realizzare correttamente la classe poodle, si scriverà quanto segue:
class poodle extends dog {
public function bark() {
print "Yip!\n";
}
public function __construct($DogName) {
parent::__construct($DogName);
print "Creating a poodle\n";
}
}
Adesso eseguendo con il codice corretto si dovrebbe ottenere il seguente output:
Creating Poppy Creating a poodle My name is Poppy. If you find me, please call 555-1234
Si noti che "Creating Poppy" viene emesso prima di "Creating a poodle", che potrebbe sembrare all'inverso, ma ha senso dato che si chiama il costruttore dog prima di eseguire qualsiasi codice di poodle. E' sempre meglio chiamare parent::__ construct() prima del costruttore di una classe figlia per assicurarsi che tutte le variabili del genitore siano impostate correttamente, e solo dopo procedere a impostare nuovo codice.
Distruttori
I costruttori sono molto utili, come abbiamo visto, ma PHP permette anche di definire il distruttore di classe, una funzione da chiamare quando un oggetto viene eliminato. PHP chiama il distruttore __destruct(), che non ha bisogno di parametri, quando gli oggetti non sono più disponibili. Ecco un semplice esempio:
public function __destruct() {
print "{$this->Name} is no more...\n";
}
Se si aggiunge questa funzione nella classe poodle, tutti i Poodle creati chiameranno questa funzione prima di essere distrutti. Se aggiungiamo questa funzione nello script di prova precedente e lo eseguiamo di nuovo, ecco quello che succede:
Creating Poppy Creating a poodle My name is Poppy. If you find me, please call 555-1234 Poppy is no more...
Così come per i costruttori, i distruttori vengono chiamati una sola volta, altrimenti è necessario utilizzare parent::__destruct(). La differenza fondamentale è che si dovrebbe chiamare parent::__destruct() dopo il codice locale per la distruzione in modo da non distruggere variabili prima di usarlo, per esempio:
public function __destruct() {
print "{$this->Name} is no more...\n";
parent::__destruct();
}
I distruttori sono utili per liberare le risorse una volta che non servono più, ma servono anche per tenere traccia degli oggetti. Dentro i distruttori è possibile eseguire tutte le azioni che si desidera e quindi è opportuno sfruttarli completamente.
A franco parlar rispondero' franche parole.
Petrarca