Operatori ed espressioni
Le costanti
Ora che tutti gli aspetti principali delle variabili sono chiariti è possibile passare al concetto opposto, ovvero le costanti. Una costante non è altro che una variabile il cui contenuto non può cambiare per alcun motivo durante l'esecuzione del programma. L'uso delle costanti è utile perché permette di parametrizzare la vostra pagina. Pensate semplicemente ad un programma che controlla una serie di dati in ingresso e controlla che i valori non superino una certa soglia. Il programma è realizzabile per esempio scrivendo il valore della soglia direttamente nel codice, ma se dovete fare decine di confronti usando lo stesso valore cosa succede quando volete cambiare questo valore? Semplicemente dovrete rileggere l'intero codice e sostituire a mano il valore. Si potrebbe pensare di utilizzare una variabile da inizializzare prima dei confronti con il valore desiderato. Questa soluzione è perfettamente legittima e funziona ma se ci pensate non è concettualmente giusta visto che il valore non cambierà mai. Per questo sono nate le costanti che in PHP vengono definite in una maniera molto simile al C tramite la funzione define() che accetta in ingresso due parametri. Il primo è il nome della costante mentre il secondo è il valore che dovrà assumere. Per richiamare una costante non si dovrà far altro che scrivere il nome questa volta senza usare il simbolo del dollaro $.
<?php
/* definisce le due costanti per il controllo dei dati */
define('PRESSURE_THRESHOLD_LO' , 75 );
define('PRESSURE_THRESHOLD_HI' , 190);
/* controlla che il valore della pressione sia nel range */
if (($val <= PRESSURE_THRESHOLD_LO) || ($val >= PRESSURE_THRESHOLD_HI))
echo "errore: pressione non nel range: $val"; /* c'è stato un errore */
?>
Esistono poi alcune costanti che il PHP stesso definisce nel momento in cui esegue un determinato script che possono essere veramente utili. Ad esempio PHP_VERSION e PHP_OS ritornano rispettivamente il numero di versione e il sistema operativo su cui il PHP viene eseguito. Possono risultare utili per permettere l'esecuzione di parti di codice che richiedono delle caratteristiche speciali di un dato sistema operativo o di una versione in particolare. Poi esistono le usatissime TRUE e FALSE il cui valore mi pare ovvio. Altre due costanti molto importanti sono __FILE__ e __LINE__ che permettono di sapere in qualsiasi momento in quale file e a quale linea ci troviamo. Per finire esistono alcune costanti che contengono eventuali messaggi di errore del PHP.
<?php echo TRUE; /* stampa sempre vero */ echo FALSE; /* stampa sempre falso */ echo PHP_VERSION; /* versione del PHP */ echo PHP_OS; /* nome del sistema operativo */ echo __FILE__; /* stampa il nome del file */ echo __LINE__; /* stampa il numero di linea corrente */ echo E_NOTICE; echo E_WARNING; echo E_ERROR; echo E_PARSE; ?>
Gli operatori
Questa parte del corso, è più che altro una carrellata di vari operatori che sono simili a quelli del C quindi se già conoscete a fondo questo argomento potete passare anche oltre. Prima di incominciare però è meglio fare un po' di chiarezza su dei termini che useremo più avanti. Esistono principalmente tre tipi di operatori: gli unari i binari e i ternari. Gli operatori unari accettano un solo argomento ad esempio l'operatore di incremento. Gli operatori binari accettano due operatori, si tratta dei più comuni ed intuitivi. Un esempio di operatore binario è la somma tra due numeri. Esistono poi alcuni operatori che accettano tre operatori in ingresso, nel corso vedremo l'unico presente in PHP ovvero quello della scelta condizionata.
Operatore di assegnazione
Forse il più semplice operatore in assoluto. Conosciuto dai matematici come operatore di identicità, la sua unica funzione è quella di rendere uguali due variabili. Essendo le variabili in gioco 2 si tratta di un operatore binario. Questo viene spesso confuso con l'operatore logico di uguaglianza da chi proviene da linguaggi come il Visual Basic in cui i due risultano uguali. Come ultima nota sappiate che l'operatore copia il valore sorgente in quello di destinazione creando una nuova variabile. Le due variabili risultano cosi disgiunte e le modifiche fatte ad una non si riflettono sull'altra.
<?php /* Operatore di Assegnazione */ $x = 2; // assegna alla variabile $x il valore 2 $x = $y = $z = 0; // Assegna a $x, $y, $z il valore 0 ?>
Operatori aritmetici
Evito di scendere nei dettagli perché sarebbe un insulto alla vostra intelligenza. Funzionano esattamente come gli operatori di aritmetica che si usano a scuola fin dalle elementari. Sono i vari operatori di somma, prodotto, sottrazione e divisione. Si tratta di operatori binari. Esistono però alcune particolarità da tenere a mente. L'operatore di modulo lavora solo su integer quindi anche se passate due float questo ritornerà sempre un numero intero. Se necessitate di maggiore precisione usate la funzione fmod(). In alcuni linguaggi esiste l'operatore di esponente che permette di elevare un numero ad una certa potenza. In PHP questo non esiste e si deve usare la funzione pow() i cui parametri sono il numero e l'esponente.
<?php $a = 7; $b = 3.2; /* Operatori Aritmetici */ $x = $a + $b; // Somma "+" echo "$x"; // 10.2 $x = $a - $b; // Sottrazione "-" echo "$x"; // 3.8 $x = $a * $b; // Moltiplicazione "*" echo "$x"; // 22.4 $x = $a / $b; // Divisione "/" echo "$x"; // 2.18 $x = $a % $b; // Modulo "%" echo "$x"; // 1 $x = pow($a, $b); // Potenza. echo "$x"; // 506.19 $x = fmod($a, $b); // Modulo. echo "$x"; // 0.6 ?>
Come in C anche in PHP è possibile usare delle forme abbreviate per evitare di dover scrivere più volte lo stesso nome di variabile. Quando il primo operando e la destinazione dell'espressione sono gli stessi è possibile omettere il primo operando e usare la forma abbreviata semplicemente ponendo l'operatore prima del operatore di assegnazione. Questo giochetto funziona anche per gli operatori bitwise, gli operatori logici e quelli per stringhe.
<?php $a = 5; $b = 2; /* esempio di forma abbreviata */ $a += $b; // mette in a 7. equivale a scrivere $a = $a + $b; $a |= $b; // equivale a: $a = $a | $b; $a .= "ciao"; // unisce a e la stringa "ciao". equivale a $a = $a."ciao"; ?>
Operatori bitwise
Questo tipo di operatore è sicuramente risultato fondamentale per chiunque abbia mai lavorato a stretto contatto con l'hardware. Grazie a questi operatori possiamo infatti manipolare i bit di cui sono composti i numeri in varie maniere. Da notare che in PHP anche le stringhe sono affette da questi operatori. Anche in questo caso si tratta di operatori binari. Oltre ai blasonati and, or e not sono presenti anche degli operatori di shift a destra e a sinistra e l'operatore xor. Sono incredibilmente utili quando si ha bisogno di fare del masking oppure se si è interessati a fare dei giochini matematici come ad esempio scambiare due variabili senza usarne una terza.
<?php $a = 2; $b = 4; /* Operatori Bitwise */ $x = $a << $b; // Siftleft "<<" echo "$x"; // 32 $x = $a >> $b; // Siftright ">>" echo "$x"; // 0 $x = $a & $b; // And "&" echo "$x"; // 0 $x = $a | $b; // Or "|" echo "$x"; // 6 $x = ~$a; // Not "~" echo "$x"; // -3 $x = $a ^ $b; // Xor "^" echo "$x"; // 6 ?>
Per chi è un po' a digiuno di assembly oppure non lo ha mai fatto gli operatori bitwise possono risultare non immediati cosi ora cercherò di spiegare brevemente come lavorano. Dobbiamo dire prima di tutto che questi operatori operano sui singoli bit che compongono un numero fregandosene bellamente che esso sia un carattere, un float o un intero.
Incominciamo con il più semplice. L'operatore Not. Questo operatore prende un bit e lo fa diventare il suo opposto quindi gli uno diventano zero e viceversa. L'operatore Or esegue una somma sui singoli bit cosi ogni volta che in $a o in $b è presente un bit a 1 l'operatore ritorna 1. L'And invece ritorna 1 se e solo se in entrambi gli operandi il bit è a 1. Lo Xor o Excluve Or è un operatore davvero singolare in quanto ritorna 1 quando i bit dei due operandi sono diversi e 0 quando sono uguali. Gli operatori di shift sono piuttosto semplici visto che l'unica operazione che compiono è introdurre un determinato numero di zeri o da destra o da sinistra spostando di conseguenza tutto il contenuto della variabile in una direzione o nell'altra.
<?php $a = 1432; // bit: 0000 0101 1001 1000 $b = 131; // bit: 0000 0000 1000 0011 // Or echo $a | $b,""; // 1435: bit: 0000 0101 1001 1011 // and echo $a & $b,"\n"; // 128: bit: 0000 0000 1000 0000 // not echo ~$a,""; // -1433: bit: 1111 1010 0110 0111 // xor echo $a ^ $b,""; // 1307: bit: 0000 0101 0001 1011 // shift left di 2 echo $a << 2,""; // 5728: bit: 0001 0110 0110 0000 ?>
Volevo far notare una cosa molto interessante nell'ultima riga quella con l'operatore di shift. Forse alcuni si saranno già accorti che ogni volta che introduciamo uno zero da destra il numero viene moltiplicato per due. Nel nostro caso introducendo 2 zeri abbiamo moltiplicato l'argomento per 4. Lascio a voi scoprire cosa succede quando si introducono degli zeri da sinistra ;).
Operatori di confronto
Ecco un punto fondamentale della programmazione imperativa. Se abbinati alle strutture di controllo e agli operatori logici vi permettono di modificare il flusso del programma cambiando il suo comportamento in base ai valori assunti dalle variabili. Questi operatori binari eseguono un confronto tra i due operandi e ritornano vero o falso a seconda che una data condizione. Esistono operatori di maggiore, minore, diverso da e uguaglianza. Proprio su quest ultimo però ci dobbiamo soffermare un' attimo per indicare una particolarità del PHP. Se usiamo l'operatore di uguaglianza con una stringa '10' e un intero 10 questo ci ritornerà TRUE. Se intendiamo che PHP tenga in considerazione anche il tipo di variabile dobbiamo usare l'operatore di identicità.
<?php
function b2s($a)
{
return ($a) ? "TRUE" : "FALSE";
}
$a = 10;
$b = '10';
/* Operatori di confronto */
$x = $a == $b; // Uguale "=="
echo b2s($x); // TRUE
$x = $a === $b; // Identico "==="
echo b2s($x); // FALSE
$x = $a != $b; // Diverso "!="
echo b2s($x); // FALSE
$x = $a <> $b; // Diverso "<>"
echo b2s($x); // FALSE
$x = $a !== $b; // Non Identico "!=="
echo b2s($x); // TRUE
$x = $a <= $b; // Minore o uguale "<="
echo b2s($x); // TRUE
$x = $a >= $b; // Maggiore o uguale ">="
echo b2s($x); // TRUE
$x = $a > $b; // Maggiore ">"
echo b2s($x); // FALSE
$x = $a < $b; // Minore "<"
echo b2s($x); // FALSE
?>
Operatori logici
I precedenti operatori di confronto sono molto utili ma ci permettono di verificare una singola condizione per volta. Cosa succede se vogliamo eseguire un frammento di codice se e solo se 3 condizioni risultano vere? con i soli operatori di confronto non è possibile. Se usiamo invece anche gli operatori logici tutto risulta più facile. Grazie a questi operatori binari possiamo combinare nelle maniere più fantasiose e varie i confronti. Anche qui il PHP ci permette di usare vari stili. Possiamo ad esempio usare direttamente le parole and, or, xor oppure gli operatori come in C. Come nota conclusiva è bene dire che le due versioni degli operatori non sono esattamente uguali avendo una precedenza diversa.
<?php
function b2s($a)
{
return ($a) ? "TRUE" : "FALSE";
}
$a = TRUE;
$b = FALSE;
/* Operatori Logici */
$x = ($a and $b); // And "and"
echo b2s($x); // FALSE
$x = ($a or $b); // Or "or"
echo b2s($x); // TRUE
$x = ($a xor $b); // Xor "xor"
echo b2s($x); // TRUE
$x = !$a; // Not "!"
echo b2s($x); // FALSE
$x = $a && $b; // And "&&"
echo b2s($x); // FALSE
$x = $a || $b; // Or "||"
echo b2s($x); // TRUE
?>
Tra gli operatori logici c'è anche l'unico operatore ternario del PHP. Quello della scelta condizionata è un' operatore utile per sostituire una struttura di controllo come la If quando risulta estremamente semplice. Riceve in ingresso un valore booleano e a seconda di questo valore ritorna il secondo ho il terzo argomento. Come vedete ci permette di scegliere tra due valori a seconda che un' altro sia vero o false. L'operatore è composto da due simboli. A sinistra di ? va inserito il valore booleano mentre a destra dello stesso vanno elencate le due alternative. Per separare i due risultati possibili usate il simbolo :.
Operatori di incremento e decremento
Eccoci arrivati ai famigerati operatori unari. Benché possano sembrare semplici non dobbiamo farci ingannare questi sono per esperienza i più infimi e sono spesso la causa di molti bug. Il loro scopo è quello di incrementare o decrementare di 1 una determinata variabile. Ne esistono però due versioni. Quelle post-fisse e quelle prefisse. La differenza tra la due versioni è veramente semplice. La prima ritorna il valore e solo dopo incrementa la variabile mentre la seconda prima incrementa e poi ritorna il valore. Quando usate questi operatori fate particolarmente attenzione ai vari side-effect che introducono.
<?php $a = 10; /* Operatori di incremento e decremento */ // Incremento prefisso echo ++$a; // stampa 11 // Incremento post-fisso echo $a++; // stampa 11 // Decremento prefisso echo --$a; // stampa 11 // Decremento post-fisso echo $a--; // stampa 11 ?>
Operatori per stringhe
Soffermiamoci ora sugli operatori propri delle stringhe. A dire il vero li abbiamo già visti durante il corso e già approfonditi. Questi due operatori sono il punto . per unire più stringhe tra loro e i tre segni di minore <<< per le stringhe heredoc. Non hanno particolarità che non abbiamo già menzionato quindi proseguiamo oltre.
<?php /* operatori di stringhe */ echo "ciao". " come ". "stai?"; // concatena 3 stringhe e ne forma una sola grazie all'operatore "." /* esempio heredoc */ echo <<<EOF classico esempio di heredoc EOF; ?>
Operatori di esecuzione
L'operatore di esecuzione è un operatore molto speciale che permette di eseguire programmi esterni e riceverne l'output all'interno di una variabile. Utilizzarlo è molto semplice. Basta infatti racchiudere il comando tra due back-ticks `. Questo operatore va usato con molta cautela e può portare a grossi problemi di sicurezza. Ricordate inoltre che tutti i programmi che fate partire tramite questo operatore partono con gli stessi permessi del server web. Nella maggior parte dei casi su sistemi unix-like apache viene fatto partire con gruppo e utente nobody:nouser quindi la maggior parte delle cartelle e file vi saranno inaccessibili. Su Windows il discorso cambia un po' e il rischio di fare dei danni anche molto seri al sistema è presente. Se volete evitare di inserire il percorso completo ricordate di inserire l'eseguibile nel PATH di sistema.
<?php /* operatore di esecuzione */ $res = `ls -lha`; // esegue ls e copia l'output in $res echo "<pre>$res</pre>"; // stampa $res ?>
Operatori di controllo degli errori
PHP possiede anche un' operatore in grado di controllare gli errori. La chiocciola @ se posta come prefisso a qualsiasi cosa possa generare un errore lo sopprimerà copiando il messaggio di errore nella variabile globale $php_errormsg (la funzione track_errors deve essere abilitata in php.ini). Usate questo operatore con attenzione e se lo fate controllate la variabile $php_errormsg subito perché il contenuto viene cancellato ad ogni errore. Come sostituto a questo operatore è possibile impostare una propria funzione personalizzata che gestisce tutti gli errori che avvengono. Dopo aver creato la propria funzione basta usare set_error_handler() per indicare al PHP che deve usarla come error handler.
<?php
/* operatori di controllo degli errori */
$conn = @mysql_connect('host', 'user', 'pass') or die('No! non si connette !!!');
/* anche se avviene un' errore il php non lo visualizzerà */
$fd = @fopen('file_che_non_esiste.estensione', 'r');
?>
In questo esempio abbiamo introdotto una cosa molto carina per la gestione degli errori che è tipica del Perl e del php. Ovvero l'accoppiata or die. Nel nostro caso se la funzione che connette al database MySQL ritorna un errore di qualsiasi genere lo script viene ucciso all'istante visualizzando un messaggio a nostro piacere.
Operatori di cast
Per ultimi ma non perché meno importanti ci sono gli operatori di cast. Questi speciali operatori permettono di convertire una determinata variabile da un tipo ad un' altro. Sono degli operatori unari perché accettano in ingresso un solo operatore. Gli operatori di cast sono veramente semplici. Basterà infatti far precedere alla variabile che vogliamo convertire il nome del tipo racchiuso tra parentesi tonde.
<?php /* Operatori di cast */ $a = '10'; /* converte $a in un intero. sono ammessi: (int) che (integer) */ $a = (int)$a; $a = (integer)$a; /* converte $a in un float. sono ammessi: (float), (real) o (double) */ $a = (double)$a; $a = (real)$a; $a = (float)$a; /* converte $a in una stringa */ $a = (string)$a; /* converte $a in un array */ $a = (array)$a; /* converte $a in un oggetto */ $a = (object)$a; /* converte $a in un boolean. sono ammessi (bool) e (boolean) */ $a = (bool)$a; $a = (boolean)$a; ?>
Associatività e precedenza
Ecco un punto fondamentale della lezione. Queste cose vanno conosciute a memoria se si intende fare qualcosa seriamente altrimenti non si andrà facilmente oltre al 2 + 2. Prima di tutto chiariamo cosa sono l'associatività e la precedenza. Associatività e la precedenza di ogni operatore sono definite nel PHP esattamente come in algebra e ci permettono di scrivere espressioni complesse molto facilmente. L'interprete divide infatti tutti gli operatori che abbiamo visto in vari gruppi con priorità diversa. Ad esempio il gruppo di precedenza A avrà priorità maggiore del gruppo B quindi quando verrà effettuata la valutazione dell'espressione per trovarne il risultato tutti gli operatori del gruppo A saranno applicati per primi. tramite l'associatività dei vari operatori l'interprete sa invece come comportarsi quando incontra due operatori che appartengono allo stesso gruppo di precedenza. Qui di seguito riporto una piccola tabella con tutti gli operatori visti in lezione con la rispettiva associatività e gruppi di precedenza. Tutti gli operatori sono in ordine crescente quindi i primi sono quelli con precedenza più bassa.
| Associatività | Operatori |
|---|---|
| Sinistra | , |
| Sinistra | or |
| Sinistra | xor |
| Sinistra | and |
| Destra | |
| Sinistra | = += -= *= /= .= %= &= |= ^= ~= <<= >>= |
| Sinistra | ? : |
| Sinistra | || |
| Sinistra | && |
| Sinistra | | |
| Sinistra | ^ |
| Sinistra | & |
| Non associativi | == != === !== |
| Non associativi | < <= > >= |
| Sinistra | << >> |
| Sinistra | + - . |
| Sinistra | * / % |
| Destra | ! ~ ++ -- (int) (float) (string) (array) (object) @ |
| Destra | [ |
| Non associativi | new |
Quando si vuole per qualche motivo forzare l'interprete a valutare un espressione prima delle altre basta racchiuderla tra parentesi tonde proprio come in matematica. Le prime volte è utile anche costruirsi l'AST (abstract syntax tree) e fare una navigazione post-order del espressione per prendere familiarità con operatori, associatività e precedenza.
<?php
/* esempio di espressioni */
$a = 5 && 10;
$a = 5 and 10; /* questa espressione non ha lo stesso effetto della precedente
l'operatore and ha una precedenza minore di quello di assegnazione */
$a = (5 and 10); // questa è corretta
$x = 10 + 4 * 2; // il risultato è 18 e non 28. l'operatore di moltiplicazione ha priorità maggiore
$k = ~$x++; /* l'operatore "~" e "++" hanno la stessa precedenza.
Hanno associatività a destra quindi il "++" viene applicato per prima */
$z = 4 + (4 * 2);
/* AST e post-order dell'espressione precedente:
+------------+
| <op-exp> |
+------------+
7 / | \
/ | \
/ | \
+---+ +---+ +-------------+
| 4 | | + | | <op-exp> |
+---+ +---+ +-------------+
1 2 6 / | \
/ | \
/ | \
+---+ +---+ +---+
| 4 | | * | | 2 |
+---+ +---+ +---+
3 4 5
*/
?>
Alla prossima lezione.