Costruttore
Molto spesso ogni volta che creiamo un’istanza di una classe, abbiamo bisogno che venga eseguita una qualche impostazione, per esempio recuperare una certa info dal database oppure inizializzare alcune proprietà. Lo possiamo fare creando un metodo speciale detto costruttore attraverso la funzione __construct()
.
class A { private $_name; public function __construct($name = NULL) { $this->_name = $name; } } $a = new A('Samuele');
Nell’esempio il metodo __construct()
sarà invocato automaticamente ogni volta che creiamo una nuova istanza della classe A
. E’ importante capire che prima di new A()
l’oggetto non esisteva, questo rende il costruttore diverso da ogni altro metodo di istanza.
Si tratta di un “metodo magico” ed è disponibile dalla versione 5 di PHP. In precedenza l’inizializzazione del codice di un oggetto seguiva uno stile simile al C++ dove il nome del metodo corrispondeva al nome della classe.
class A { private $_name; public function A($name = NULL) { $this->_name = $name; } }
Per retrocompatibilità PHP 5, ogni volta che viene creato un oggetto, prima cercherà di eseguire una funzione __construct()
, nel caso non la trovi cercherà una funzione con lo stesso nome della classe.
Ereditarietà
A differenza di linguaggi come C++ il costruttore (ed il distruttore) in PHP può essere ereditato nelle sottoclassi, evitando così di doverne riscrivere il codice:
class A { private $_name; public function __construct() { $this->_name = 'Rossana'; echo $this->_name; } } class B extends A { } $b = new B(); //echo Rossana
La classe B
non avrà bisogno di ridefinire il costruttore, che sarà ereditato dalla classe genitore. Inoltre, anche se non è buona pratica farlo, il costruttore potrà essere marcato come final
, abstract
o static
o addirittura essere definito nelle interfacce.
Namespace
A partire da PHP 5.3.3, in caso di classi sotto un namespace, i metodi con lo stesso nome della classe non saranno più trattati come un costruttore. Questo non vale per classi non-namespaced.
namespace Test; class A { public function A() { } }
Nel precedente esempio il metodo A
sarà trattato come costruttore da PHP 5.3.0-5.3.2 e come metodo normale da PHP 5.3.3
Overloading
Attualmente PHP non supporta l’overloading dei metodi. Lo stesso discorso vale per il costruttore.
Questa è una delle critiche che sono tutt’ora mosse al linguaggio dal punto di vista OOP. Tra i vari “trucchi” che possiamo usare per quantomeno simulare una sorta di overloading del costruttore, il seguente rappresenta senz’altro una buona pratica:
class A { public function __construct($param) { if (is_int($param)) { /* ... */ } elseif (is_string($param)) { /* ... */ } elseif (is_array($param)) { /* ... */ } } }
In questo caso la firma (signature) del costruttore non cambia, ma sono in realtà rappresentate tre firme che potranno essere descritte nel DocBlock.
Overriding
Possiamo eseguire l’overriding di un costruttore nelle sottoclassi, proprio come avviene per gli altri metodi, utilizzando quindi il nome speciale parent per conservare la funzionalità fornita dalla classe genitore:
class A { public function __construct() { //Setup A } } class B extends A { public function __construct() { parent::__construct(); //Setup B } } class C extends B { public function __construct() { A::__construct(); //Setup C } }
Da notare come nell’esempio precedente il costruttore della classe C
preserva le funzionalità della classe A
ma non di quella genitore, cioè B
.
Distruttore
Con PHP 5 è stato introdotto il concetto del distruttore, già presente negli altri linguaggi OOP. Le istanze di una classe che il programma crea, sono rimosse dalla memoria quando la pagina ha terminato l’esecuzione, o quando la variabile (che contiene l’istanza) viene impostata in modo esplicito su NULL (oppure assume un valore non valido). Il distruttore (__destruct()
) è un metodo, senza parametri, che viene chiamato (se presente) automaticamente immediatamente prima che l’oggetto sia distrutto.
Si tratta di un metodo particolarmente utile per eseguire pulizie dell’ultimo minuto, per esempio chiudere le connessioni a database o gli handle dei files, che potevano essere stati aperti dalla classe, oppure qualsiasi altra operazione che riteniamo utile che sia eseguita prima che l’oggetto venga distrutto.
class A { public function __destruct() { echo "L'istanza di " . __CLASS__ . " e' appena stata distrutta."; } }
Ereditarietà
Come per il costruttore, in una sottoclasse, il distruttore genitore non sarà chiamato implicitamente in caso di ridefinizione del metodo, ma dovremo farlo esplicitamente attraverso la chiamata a parent::__destruct()
nel corpo del distruttore.