[PILLOLE PHP] Lo scope
Un argomento che può risultare ostico al pricipiante (o che perlomeno può indurlo a commettere degli errori banali o a perdere tempo) é senz’altro lo scope, ovvero l’ambito di validità di una variabile. Nell’esecuzione di uno script infatti una variabile potrebbe avere diversi significati a dipendenza di dove viene dichiarata..
Iniziamo dunque a vedere quali sono i tre possibili scope di una variabile:
- Globale: una variabile si dice globale quando é dichiarata nello script principale (all’interno delle funzioni non avrà nessun valore);
- Locale: si dice locale una variabile dichiarata all’interno di una funzione (all’esterno della funzione non avrà nessun valore);
- Super-globale: le variabili super-globali sono quelle gestite da PHP ($_SESSION, $_SERVER, $_POST, $_GET, $_REQUEST, $_COOKIE, $_ENV, $_FILES, $GLOBALS). L’ambito di validità delle variabili super-globali é totale, cioé sono valide sia all’interno che all’esterno delle funzioni. Inoltre va considerato che anche le costanti hanno un abito di validità super-globale.
Ma facciamo subito degli esempi.
Le variabili globali non sono disponibili in ambito locale
Come abbiamo già detto, le variabili globali non sono disponibili in ambito locale.
Guarda l’esempio spiegato di seguito:
$var = “Hello”; // $var é dichiarata in abito globale function Test() { // alla funzione Test() si richiede si stampare $var // ma siamo all’interno di una funzione // che non ha accesso alle variabili globali echo $var; } // di conseguenza, invocando la funzione Test() // verrà sollevato un errore ($var non é definita) Test();
Le variabili locali non sono disponibili in ambito globale
Analizziamo l’esempio che segue per capire cosa intendiamo quando diciamo che le variabili locali non sono disponibili in ambito globale:
function Test() { //La funzione Test() ha lo scopo di valorizzare la variabile $var $var = "Hello"; } // Invocando la funzione Test(), $var viene valorizzata // ma solo in ambito locale Test(); // dunque tentare di stamparla a video // in ambito globale produrrà un errore // $var non risulta definita echo $var;
Quindi riassumendo possiamo dire che una funzione, per quanto concerne le variabili, é chiusa ermeticamente rispetto al resto del codice.
Le variabili super-globali sono disponibili ovunque
Adesso, andiamo a dare uno sguardo alle variabili super-globali:
define('MIA_COSTANTE', 'Hello'); function Test() { echo MIA_COSTANTE . ': MIA_COSTANTE in ambito locale<br />'; echo $_SERVER['PHP_SELF'] . ': PHP_SELF in ambito locale<br />'; } Test(); echo MIA_COSTANTE . ': MIA_COSTANTE in ambito globale<br />'; echo $_SERVER['PHP_SELF'] . ': PHP_SELF in ambito globale'; //Il risultato sarà // Hello: MIA_COSTANTE in ambito locale //test.php: PHP_SELF in ambito locale //Hello: MIA_COSTANTE in ambito globale //test.php: PHP_SELF in ambito globale
Come far cadere le barriere tra ambito globale ed ambito locale?
E’ possibile fare in modo che una variabile globale sia resa disponibile anche all’interno di una funzione tramite la keyword global; vediamo come:
// $var é dichiarata in ambito globale $var = "Hello"; function Test() { // Nella funzione Test() dichiaro di voler // utilizzare la variabile globale $var global $var; // Ora $var é disponibile e può essere utilizzata $var .= " World"; } Test(); // Verrà stampato "Hello World" echo $var;
E’ possibile ottenere lo stesso risultato utilizzando l’array $GLOBALS, difatti l’array $GLOBALS è una variabile automaticamente disponibile in tutti gli ambiti senza doverla dichiarare globale per accedervi dall’interno di una funzione.
$var = "Hello"; function Test() { $GLOBALS['var'] .= " World"; } Test(); echo $var;
Considera comunque che rompere gli argini tra ambito locale ed ambito globale é un’operazione da evitare finché é possibile.
Perché l’utilizzo di global é da evitare?
Come detto, per quanto possibile, é meglio evitare l’utilizzo delle tecniche appena descritte.
La netta distinzione di ambiti tra il locale e il globale, che al profano può sembrare un’inutile seccatura, ha delle ragioni molto precise.
Le funzioni generalmente rappresentano una parte di codice molto specifica della quale intravvediamo spesso dei possibili riutilizzi.
Dal momento che:
- non sappiamo quando e in che circostanza potrebbe tornarci utile questa funzione;
- nel caso in cui stiamo lavorando in team ad un grande progetto, potrebbe anche accadere che questa funzione venga riutilizzata da qualcun’altro;
è bene che la funzione sia il più robusta possibile. Global inevitabilemente introduce delle ambiguità e potrebbe portare all’interno della funzione dei valori non corretti.
Una funzione invece, di principio, riceve i dati come argomenti e li restituisce attraverso la keyword return. E questo basta per garantirle la robustezza che auspichiamo.
Per concludere vediamo come passare correttamente gli argomenti ad una funzione.
Argomenti, argomenti facoltativi, argomenti arbitrari
Vediamo brevemente e in pratica come passare gli argomenti ad una funzione in tre diversi casi.
SOMMA DI DUE NUMERI
function Somma($a,$b) { return $a + $b; } echo Somma(5,9);
SOMMA DI DUE O TRE NUMERI (argomenti facoltativi)
//il terzo parametro ($c) lo dichiariamo come //uguale a 0. In questo modo se non verrà inserito //nulla avrà valore 0 e non influirà sulla somma //mentre se passeremo anche il terzo argomento //questo andrà a sovrascrivere la variabile $c function Somma($a,$b,$c = 0) { return $a + $b + $c; } echo Somma(6,2); echo Somma(5,9,6);
SOMMA DI X NUMERI (argomenti arbitrari)
function Somma() { $args = func_get_args(); $return = 0; foreach($args as $value) { $return = $return + $value; } return $return; } echo Somma(2,3,4,5,9,0,0,2);
Conclusione
In questo articolo abbiamo visto alcune caratteristiche fondamentali del liguaggio. La logica degli ambiti di validità delle variabili riveste infatti una notevole importanza nello sviluppo di un codice robusto. Spero di aver chiarito questo argomento che, come ho detto all’inizio, risulta spesso essere un punto critico per i principianti.
15 commenti
Trackback e pingback
-
Raccolta di articoli della settimana 12-19/06/2011 | Saverio Gravagnola
[...] scope in PHP (Your Inspiration [...]
Fantastico Maurizio!!!!
Conoscevo già l’argomento, ma devo dire di aver fatto un ottimo ripasso, non ho ancora trovato nessuno che spieghi il php in maniera così chiara e semplice, molti mettono solo una marea di codice senza spiegare un’acca, complimenti ancora :)
P.S.: A quando un articolo sullo scope in Javascript (la parolina “this” per intenderci)? Quello proprio non mi entra in testa :(
Quoto Tizionario sullo scope in Javascript!
Per il resto, come al solito grande Maurizio!
Grazie Tiziano e lxn.
Per javascript il discorso é leggermente diverso ed é più legato alle funzioni. Magari un giorno ne parliamo.
Ciao Maurizio, in questi giorni mi trovo alle prese con PHP per un esame.. Mi è stato molto utile il tuo articolo. Grazie ;-)
Molto bene, grazie daniele.
Ciao Maurizio,
alla luce di questo articolo mi sorge spontanea la domanda: “come mai WordPress fa un utilizzo massiccio di global?”
In questo caso é inevitabile ma non “rischiso”.
Se vuoi sviluppare un tema o un plugin per WP ne devi conoscere la struttura e le risorse che mette a disposizione.
Ad esempio WP mette a disposizione la variabile $wp_locale, che é un oggetto contenente delle informazioni.
1. non utilizzerò mai una variabile che si chiama wp_locale (sto lavorando in un ambiente standard, che conosco e quindi so cosa posso o non posso utilizzare)
2. Anche se dovessi farlo non succederebbe nulla, in quanto programmare per WP significa farlo attraverso delle funzioni che verranno poi implementate da altre funzioni native di WP (add_action, add_filter), dunque un eventuale $wp_locale nella funzione di un plugin non andrebbe a confliggere con $wp_locale messo a disposizione da WP
3. In conclusione utilizzo global per poter utilizzare nelle mie funzioni delle risorse messe a disposizione da WP
Semplicemente con WP ci troviamo all’interno di un framework che ha le sue regole precise. Se le conosciamo e le rispettiamo non andiamo incontro a nessun rischio.
ciao Maurizio,
hai toccato un argomento che ritengo fondamentale ma sul quale ho dei dubbi sul modo in cui opero.
global è sempre da evitare finché é possibile: ho sempre seguito questa regola.
Generalmente, però, io nello sviluppo dei miei siti vi è un unica variabile che richiamo con global all’interno delle mie classi: l’istanza del PDO http://php.net/manual/en/book.pdo.php
In pratica creo un file load.php che verrà incluso in tutte le pagine e al suo interno inserisco le seguenti istruzioni:
– session_start(): per avere le sessioni aperte in tutte le pagine;
– set_error_handler: per gestire gli errori in produzione/sviluppo;
– inclusione del config.php: una serie di define…
– istanza del PDO;
– funzione __autoload: per l’inclusione automatica delle classi istanziate;
A questo punto per interagire con il db all’intenro delle classi che sviluppo faccio
global $PDO;
(generalmente all’interno del costruttore della classe).
In questo modo evito di dover passare $PDO come argomento dei metodi delle classi (e senza fare exstends della classe PDO).
Puoi darmi un parere, un consiglio sul mio modo di agire.
Quali “alternative” vi sarebbero?
Ciao oly.
Se si tratta di un insieme di codici interamente gestito da te é diverso da uno script destinato ad essere distribuito.
Anche in questo caso comunque, io preferisco evitare il global.
Trovo più chiaro (ma é soggettivo) vedere l’istanza entrare nella classe dal costruttore piuttosto che materializzarsi con un global.
Questo fa parte anche del mio stile di programmazione che é molto descrittivo.
Complimenti.. finalmente ho avuto conferma di quello che pensavo.. nessuno era riuscito a spiegarlo così bene e semplicemente..
Ma le variabili ti tipo local devono avere sempre il return per restituire appunto l’elaborazione della variabile ? Dai primi esempi che hai illustrato mi sembra di no
Se è no, quando utilizzare il return allora ?
Grazie
Domanda interessante che presuppone una risposta approfondita.
Le funzioni lasciano una certa libertà e il come le utilizziamo dipende molto da quello che vogliamo farcene.
Possiamo avere funzioni che non prendono paramentri e non restituiscono nulla
Possiamo avere funzioni che ritornano qualcosa sottoforma di output a video
Ed esistono funzioni che ritornano un valore
Quindi return non é obbligatorio, anche se c’é chi lo mette comunque alla fine di una funzione.
Una cosa importante va comunque detta sulla keyword return. Con essa si chiede a PHP di tornare all’ambiente globale interrompendo di fatto l’esecuzione della funzione.
In questa funzione, dopo una prima elaborazione, viene verificato se $x vale 5. Se sì, PHP torna allo script globale ignorando il codice che segue (//altro codice).
Grazie infinite per la esaudiente risposta.. quindi da quello che ho compreso RETURN viene utilizzato quando la funzione può servire per valorizzare una variabile o al verificarsi di determinate condizioni, altrimenti non si usa o comunque non è obbligatorio il suo utilizzo
Mentre nell’ultimo esempio (credo cosa importantissima che hai fatto rilevare: il ritorno all’ambiente globale ) se verificata la condizione effettua una specie di salto del codice..
Esatto, return fa due cose: porta un valore all’esterno della funzione e determina la fine dell’esecuzione della funzione ed il relativo ritorno all’ambiente globale.
Grazie :)