Iterazione attraverso le variabili oggetto
Guardando attentamente il PHP, un oggetto non è poi così diverso da un array, un oggetto infatti, a parte i puntatori alle funzioni della sua classe, memorizza solo delle variabili. Il risultato è che si può trattare un oggetto con un ciclo foreach, come se fosse un array, attraversando tutte le sue variabili interne, purché siano accessibili. Cioè le variabili private e quelle protette non saranno accessibili nella carrellata esplorativa. Diamo un'occhiata a questo script:
<?php
class person {
public $FirstName = "Carlo";
public $MiddleName = "Maria";
public $LastName = "Salerno";
private $Password = "Sasa25";
public $Age = 29;
public $HomeTown = "Torino";
public $FavouriteColour = "Verde";
}
$item = new person();
foreach($item as $var => $value) {
echo "$var is $value\n";
}
?>
Dopo averlo salvato ed avviato, questo dovrebbe essere il risultato:
FirstName is Carlo MiddleName is Maria LastName is Salerno Age is 29 HomeTown is Torino FavouriteColour is Verde
Notiamo che la variabile $Password non è visibile, perché è contrassegnata come private e stiamo cercando di accedervi da un campo di applicazione globale. Se modifichiamo leggermente lo script in modo che il ciclo foreach venga chiamato dall'oggetto stesso, dovremmo essere in grado di vedere la variabile:
<?php
class person {
public $FirstName = "Carlo";
public $MiddleName = "Maria";
public $LastName = "Salerno";
private $Password = "Sasa25";
public $Age = 29;
public $HomeTown = "Torino";
public $FavouriteColour = "Verde";
public function outputVars() {
foreach($this as $var => $value) {
echo "$var is $value\n";
}
}
}
$item = new person();
$item->outputVars();
?>
Ed ecco l'output:
FirstName is Carlo MiddleName is Maria LastName is Salerno Password is Sasa25 Age is 29 HomeTown is Torino FavouriteColour is Verde
Adesso che è l'oggetto stesso che effettua il ciclo attraverso le sue variabili, possiamo vedere bene anche le variabili private. Questo modo di effettuare i cicli attraverso gli oggetti è molto utile per scrivere delle funzioni di serializzazione, basta ricordarsi di mettere la funzione all'interno dell'oggetto, altrimenti i dati privati e protetti verranno ignorati.
Informazioni sul tipo oggetto
Come abbiamo visto, l'ereditarietà da una classe ad un'altra è un modo incredibilmente potente per costruire funzionalità articolate negli script PHP. Tuttavia molto spesso è facile perdersi tra i rami delle eredità , come fare allora a risalire alle classi di provenienza ?
Un primo aiuto può venire dalla funzione is_subclass_of, definita da:
bool is_subclass_of (mixed object, string class_name)
che restituisce true se la classe indicata come secondo parametro ha tra i suoi antenati la classe indicata come primo parametro.
Provare il codice seguente:
<?php
class TestClass { // definisce una classe
var $prova = 'uno';
}
class TestClass_Child extends TestClass { // definisce una classe figlia
var $prova = 'prova';
}
$TC = new TestClass(); // crea un nuovo oggetto
$TCC = new TestClass_Child();
if (is_subclass_of($TCC, 'TestClass')) {
echo "si, \$TCC è una subclass di TestClass<br>";
}
else {
echo "no, \$TCC non è una subclass di TestClass<br>";
}
if (is_subclass_of($TC, 'TestClass')) {
echo "si, \$TC è una subclass di TestClass<br>";
}
else {
echo "no, \$TC non è una subclass di TestClass<br>";
}
?>
Verrà prodotto il seguente output:
si, $TCC è una subclass di TestClass no, $TC non è una subclass di TestClass
Oltre alla soluzione precedente, PHP fornisce anche la parola chiave speciale, instanceof, che può essere utilizzata come un operatore. Una sua applicazione restituirà true se l'oggetto sul suo lato sinistro risulta essere della stessa classe o un discendente della classe indicata sul suo lato destro. Ad esempio, se consideriamo come punto di partenza il codice:
$poppy = new poodle;
si avrà che le due righe
if ($poppy instanceof poodle) { }
if ($poppy instanceof dog) { }
saranno valutate entrambe come true, perchè $poppy è un oggetto della classe poodle ed è, contemporaneamente, un oggetto discendente dalla classe dog.
I programmatori Java saranno felici di sapere che instanceof è la stessa vecchia conoscenza a cui si sono abituati nel corso degli anni. Si tratta di una grande parola chiave da tenere a portata di mano, vi diranno, e vi ritoverete quasi certamente ad usarla abbastanza spesso negli script.
Se si vuole solo sapere se un oggetto è un discendente di una certa classe, diversa dalla sua stessa classe, è possibile utilizzare la funzione is_subclass_of(), sul cui funzionamento ci siamo già soffermati.
Comprendere la sottile differenza tra is_subclass_of() e instanceof è molto importante, e questo script dovrebbe chiarire le idee:
<?php
class dog { }
class poodle extends dog { }
$poppy = new poodle();
print (int)($poppy instanceof poodle);
print "\n";
print (int)is_subclass_of($poppy, "poodle");
?>
Il primo output sarà 1, il secondo 0. Il casting di tipo int viene utilizzato perché altrimenti il booleano false verrebbe stampato come "" (vuoto), e invece con il casting intero diventa 0. Come si può vedere, utilizzando instanceof si ottiene true nel senso che $poppy è sia discendente da poodle sia da dog, mentre is_subclass_of() riporta false perché $poppy non discende dalla classe poodle, essendo esso stesso appartenente alla classe poodle.
Si noti che è anche possibile utilizzare la parola chiave instanceof per vedere se un oggetto implementa un'interfaccia.
Suggerimenti sul tipo della classe
Sebbene PHP rimanga un linguaggio debolmente tipizzato, il che significa, come sappiamo, che non c'è bisogno di specificare il tipo per le variabili, PHP 5 ha introdotto i suggerimenti per il tipo di classe, per consentire di specificare il tipo della classe che deve essere passata ad una funzione. Questi non sono obbligatori, e non sono neanche controllati mentre lo script viene eseguito, quindi non possono essere considerati dei controlli severi.
Con la versione PHP 5.1 questa possibilità è stata estesa anche ad elementi diversi dalle classi, come gli array. Ma vediamo questi suggerimenti in azione:
<?php
class dog {
public function do_drool() {
echo "Sluuuuurp\n";
}
}
class cat { }
function drool(dog $some_dog) {
$some_dog->do_drool();
}
$poppy = new cat();
drool($poppy);
?>
Notiamo che la funzione drool() accetta un parametro, $some_dog, e che il nome del parametro è preceduto dal suggerimento di classe. Questo significa che dovrebbe accettare un parametro solo del tipo "dog". Nell'esempio, si è supposto che $poppy fosse un oggetto cat, e così l'esecuzione darà il seguente risultato:
Fatal error: Argument 1 must be an instance of dog in classhint.php on line 12
Si noti che fornire un suggerimento di classe per un tipo di classe che non esiste causerà un errore fatale. Come potete vedere, i suggerimenti di classe sono essenzialmente un modo per evitare di utilizzare continuamente la parola chiave instanceof per verificare che le funzioni ricevano il giusto tipo di oggetto. L'uso dei suggerimenti di classe è essenzialmente un modo implicito di usare instanceof senza scrivere codice aggiuntivo. Si dovrebbe fare un uso regolare dei suggerimenti di classe in quanto sono un modo molto semplice per autoregolare il codice e per risolvere più velocemente i bug.
Così come con la parola chiave instanceof si può specificare un'interfaccia, anche i suggerimenti possono essere applicati ad un'interfaccia.
Lo Stato esiste per formar l'uomo saggio: e con l'entrata in scena dell'uomo saggio, lo Stato cessa di esistere. Il carattere rende lo Stato non più necessario. Il saggio è egli stesso lo Stato.
Ralph Waldo Emerson