Nell’articolo PHP 5 ad oggetti: programmazione con le classi ho spiegato come creare una classe in PHP. La classe di esempio aveva una serie di attributi e metodi tutti con visibilità pubblica. Ciò significa, come in tutti i linguaggi orientati agli oggetti, che è possibile accedere ad essi dall’esterno della classe.
Ovviamente ciò non è sempre desiderabile. In generale infatti l’implementazione della classe deve essere nascosta (information hiding, o incapsulamento), e deve essere possibile accedere dall’esterno solo ai metodi necessari per manipolare l’oggetto in modo controllato. In PHP, come ad esempio anche in Java e C++, è quindi possibile definire la visibilità di attributi e metodi tramite i seguenti modificatori di visibilità:
- private: l’attributo/metodo è nascosto all’esterno. E’ quindi utilizzabile solo all’interno della classe
- protected: l’attributo/metodo è nascosto all’esterno ma è visibile per tutte le sottoclassi della classe
- public: l’attributo/metodo è visibile sia all’interno che all’esterno della classe.
Questo è un esempio classico di information hiding: una classe che nasconde all’esterno i suoi attributi, ma consente la manipolazione dell’oggetto tramite alcuni metodi.
<?php
// Definizione della classe MyClass
class MyClass {
private $att1; // primo attributo
private $att2; // secondo attributo
// Costruttore
public function __construct(){
$att1 = null;
$att2 = null;
}
// Permette di impostare $att1
public function setAtt1($val){
$this->att1 = $val;
}
// Permette di impostare $att2
public function setAtt2($val){
$this->att1 = $val;
}
// Permette di leggere $att1
public function getAtt1(){
return $this->att1;
}
// Permette di leggere $att2
public function getAtt2(){
return $this->att2;
}
}
?>
In questo esempio le potenzialità dei modificatori sono molto sottovalutate, però permette di capire il funzionamento. Qualsiasi altra classe può creare un oggetto MyClass, ma non può modificare direttamente i suoi attributi $att1 e $att2. Può però impostarli e ottenerne il valore tramite i metodi setAtt1(), setAtt2(), getAtt1() e getAtt2(). Per ottenere ciò abbiamo impostato il modificatore private sui due attributi, mentre public sui metodi. In questo modo si nasconde all’esterno l’implementazione della classe. Se per esempio $att1 dovesse assumere solo particolari valori, all’interno del metodo setAtt1() potremmo controllare che il valore dato sia valido.
Notare che utilizzando i modificatori di visibilità non è più necessario usare la keyword var per definire gli attributi della classe!
Metodi privati
Supponiamo di avere bisogno di metodi di supporto per effettuare elaborazioni complesse. In questo caso sarebbe desiderabile nascondere tali metodi all’esterno, in quanto sono utili solo alla classe. Ad esempio, supponiamo che l’attributo $att1 debba sottostare ad alcune condizioni di validità abbastanza complesse, e creiamo un metodo checkAtt1() per verificare se il valore dato è valido o meno. Possiamo scrivere un codice di questo tipo:
<?php
// Definizione della classe MyClass
class MyClass {
private var $att1; // primo attributo
// Permette di impostare $att1
public function setAtt1($val){
// controllo che il valore dato sia valido
if (!$this->checkAtt1($a)){
return false;
}
$this->att1 = $val;
return true;
}
// Permette di leggere $att1
public function getAtt1(){
return $this->att1;
}
// Controlla la validità di $att1
private function checkAtt1($a){
// ... codice di controllo di $a ...
// se valido ritorno true, altrimenti false
}
}
?>
Impostando la visibilità private per il metodo checkAtt1() abbiamo impedito che esso possa essere chiamato dall’esterno. Ho volutamente escluso il costruttore, e i metodi set e get per att2 per questioni di spazio.
Nel seguente codice è possibile vedere cosa si può e cosa non si può fare su un oggetto della classe MyClass.
<?php
// Istanzio un oggetto di tipo MyClass
$obj = new MyClass();
// Modifico $att1 direttamente
$obj->att1 = 10; // Errore!!! $att1 è private
// Modifico $att1 tramite set
$obj->setAtt1(10); // Ok
// Stampo il valore impostato
echo $obj->att1; // Errore!!!
echo $obj->getAtt1(); // Ok. Stampa 10
// Chiamo checkAtt1
$obj->checkAtt1(10); // Errore!!! checkAtt1 è private
?>
Il modificatore di visibilità protected, come ho detto, permette l’utilizzo del metodo o attributo sul quale è specificato, solo all’interno della classe stessa e delle sue sottoclassi. Ne parleremo meglio in un articolo dedicato all’ereditarietà.
Visibilità di costruttore e distruttore
Se si vuole dare la possibilità di costruire un oggetto, è ovvio che il costruttore deve essere public. Ci sono casi particolari in cui però è necessario impostarlo private, ovvero nei casi in cui è solo la classe stessa a poter istanziare oggetti della classe. Il costruttore privato è usato ad esempio nel pattern Singleton, ma non è questa la sede per parlarne.
Stessa cosa per il distruttore. Se si è deciso di utilizzarlo, a meno di casi particolari, deve essere sempre public, anche se il linguaggio non impedisce di definirlo private o protected.