Riferimento: che cos'è l'ambito delle variabili, quali variabili sono accessibili da dove e quali sono gli errori di "variabile non definita"?


167

Nota: questa è una domanda di riferimento per gestire l'ambito variabile in PHP. Si prega di chiudere una delle tante domande che si adattano a questo modello come duplicato di questo.

Che cos'è "ambito variabile" in PHP? Le variabili di un file .php sono accessibili in un altro? Perché a volte ricevo errori "variabile non definita" ?


1
Se la definissi come "Variabile non definita" otterrai un sacco di hit :) buon lavoro però
Dale

@Dale, attualmente no. 2k visualizzazioni in 2 anni sono ....
Pacerier

7
@Pacerier ... circa il momento giusto per lasciare un commento casuale?
Dale,

@Pacerier Non sono davvero sicuro di quello che stai cercando di dire con quel commento. "È ...." ... cosa ?! : P
inganno

@Dale, ora è il momento giusto: wow anche se la domanda è rimasta ferma per 2 anni, dopo che la parola " apolide " è stata aggiunta al suo GoogleDex, il suo tasso di successo è letteralmente 3 volte inferiore in soli 6 mesi.
Pacerier,

Risposte:


188

Che cos'è "ambito variabile"?

Le variabili hanno un "ambito" o "luoghi" limitati da cui sono accessibili ". Solo perché hai scritto $foo = 'bar';una volta da qualche parte nella tua applicazione non significa che puoi fare riferimento $fooda qualsiasi altra parte all'interno dell'applicazione. La variabile $fooha un determinato ambito entro il quale è valida e solo il codice nello stesso ambito ha accesso alla variabile.

Come viene definito un ambito in PHP?

Molto semplice: PHP ha un ambito di funzione . Questo è l'unico tipo di separatore di ambito esistente in PHP. Le variabili all'interno di una funzione sono disponibili solo all'interno di quella funzione. Le variabili al di fuori delle funzioni sono disponibili ovunque al di fuori delle funzioni, ma non all'interno di alcuna funzione. Ciò significa che esiste un ambito speciale in PHP: l' ambito globale . Qualsiasi variabile dichiarata al di fuori di qualsiasi funzione rientra in questo ambito globale.

Esempio:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$fooè nell'ambito globale , $bazè all'interno di un ambito localemyFunc . Solo il codice interno myFuncha accesso a $baz. Solo il codice esterno myFunc ha accesso a $foo. Nessuno dei due ha accesso all'altro:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

    echo $foo;  // doesn't work
    echo $baz;  // works
}

echo $foo;  // works
echo $baz;  // doesn't work

Ambito e file inclusi

I limiti dei file non separano l' ambito:

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

Le stesse regole si applicano al includecodice d come per qualsiasi altro codice: solo functionambito separato. Ai fini dell'ambito, potresti pensare di includere file come copia e incolla codice:

c.php

<?php

function myFunc() {
    include 'a.php';

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

Nell'esempio sopra, è a.phpstato incluso all'interno myFunc, tutte le variabili all'interno a.phphanno solo un ambito di funzione locale. Solo perché sembrano rientrare nell'ambito globale a.phpnon significa necessariamente che lo siano, in realtà dipende dal contesto in cui è incluso / eseguito il codice.

Che dire delle funzioni all'interno di funzioni e classi?

Ogni nuova functiondichiarazione introduce un nuovo ambito, è così semplice.

(anonime) funzioni all'interno delle funzioni

function foo() {
    $foo = 'bar';

    $bar = function () {
        // no access to $foo
        $baz = 'baz';
    };

    // no access to $baz
}

classi

$foo = 'foo';

class Bar {

    public function baz() {
        // no access to $foo
        $baz = 'baz';
    }

}

// no access to $baz

A cosa serve l'ambito?

Affrontare i problemi di scoping può sembrare fastidioso, ma l' ambito variabile limitato è essenziale per scrivere applicazioni complesse! Se ogni variabile dichiarata fosse disponibile da qualsiasi altra parte della tua applicazione, passeresti da una parte all'altra delle variabili senza un modo reale di tracciare ciò che cambia cosa. Ci sono solo così tanti nomi sensibili che puoi dare alle tue variabili, probabilmente vuoi usare la variabile " $name" in più di un posto. Se potessi avere questo nome di variabile univoco solo una volta nella tua app, dovresti ricorrere a schemi di denominazione davvero complicati per assicurarti che le tue variabili siano uniche e che non stai cambiando la variabile sbagliata dal pezzo di codice sbagliato.

Osservare:

function foo() {
    echo $bar;
}

Se non ci fosse ambito, cosa farebbe la funzione sopra? Da dove $barviene Che stato ha? È anche inizializzato? Devi controllare ogni volta? Questo non è mantenibile. Il che ci porta a ...

Attraversare i confini dell'ambito

La strada giusta: passare le variabili dentro e fuori

function foo($bar) {
    echo $bar;
    return 42;
}

La variabile $barentra esplicitamente in questo ambito come argomento della funzione. Solo guardando questa funzione è chiaro da dove provengono i valori con cui lavora. Quindi restituisce esplicitamente un valore. Il chiamante ha la certezza di sapere con quali variabili funzionerà la funzione e da dove provengono i suoi valori di ritorno:

$baz   = 'baz';
$blarg = foo($baz);

Estensione dell'ambito delle variabili in funzioni anonime

$foo = 'bar';

$baz = function () use ($foo) {
    echo $foo;
};

$baz();

La funzione anonima include esplicitamente $foodal suo ambito circostante. Si noti che questo non è lo stesso dell'ambito globale .

La strada sbagliata: global

Come detto prima, l'ambito globale è in qualche modo speciale e le funzioni possono importare esplicitamente variabili da esso:

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}

Questa funzione utilizza e modifica la variabile globale $foo. Non farlo! (A meno che tu non sappia davvero davvero quello che stai facendo, e anche allora: non farlo!)

Tutto il chiamante di questa funzione vede questo:

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!

Non ci sono indicazioni che questa funzione abbia effetti collaterali , eppure lo fa. Questo diventa molto facilmente un pasticcio aggrovigliato poiché alcune funzioni continuano a modificarsi e richiedono uno stato globale. Volete che le funzioni siano stateless , agendo solo sui loro input e restituendo output definiti, comunque molte volte le chiamate.

Dovresti evitare di usare l'ambito globale in ogni modo il più possibile; sicuramente non dovresti "estrarre" le variabili dall'ambito globale in un ambito locale.


Hai appena detto la strada sbagliataglobal , quindi per favore dicci quando dovremmo usare global? E per favore spiega (un po ') cos'è static...?

@stack Non esiste un modo "giusto" per global. È sempre sbagliato. Il passaggio dei parametri della funzione è corretto. staticè spiegato bene nel manuale e non ha molto a che fare con l'ambito. In breve, può essere considerata una "variabile globale con ambito". Mi sto espandendo un po 'sul suo utilizzo qui kunststube.net/static .
Inganno

Il mio semplice pensiero è che se una variabile php è abbastanza importante da meritare uno stato globale, merita una colonna in un database. Forse è eccessivo, ma è un approccio infallibile che si adatta alla mia intelligenza di programmazione mediocre
Arthur Tarasov,

@Arthur C'è così tanto da disimballare lì ... ಠ_ಠ Questo non è certamente un approccio che approverei.
Inganno

@deceze un po 'di un argomento che sta accadendo qui oggi stackoverflow.com/q/51409392 - in cui il PO menziona che il duplicato (qui) non menziona include_oncee forse require_oncedovrebbe essere aggiunto da qualche parte; sto solo dicendo. Il PO ha votato per riaprire anche la loro domanda. Il loro post sarebbe un caso speciale e cosa si dovrebbe fare al riguardo?
Funk Forty Niner,

10

Sebbene le variabili definite all'interno dell'ambito di una funzione non siano accessibili dall'esterno, ciò non significa che non è possibile utilizzare i loro valori dopo il completamento di tale funzione. PHP ha una staticparola chiave ben nota che è ampiamente usata in PHP orientato agli oggetti per definire metodi e proprietà statici, ma bisogna tenere presente che staticpuò anche essere usato all'interno delle funzioni per definire variabili statiche.

Che cos'è la "variabile statica"?

La variabile statica differisce dalla variabile ordinaria definita nell'ambito della funzione nel caso in cui non perda valore quando l'esecuzione del programma lascia questo ambito. Consideriamo il seguente esempio di utilizzo di variabili statiche:

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

Risultato:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

Se avessimo definito $countersenza di staticallora ogni volta il valore echo sarebbe lo stesso del $numparametro passato alla funzione. L'utilizzo staticconsente di creare questo semplice contatore senza ulteriore soluzione.

Casi d'uso di variabili statiche

  1. Memorizzare valori tra chiamate conseguenti alla funzione.
  2. Memorizzare valori tra chiamate ricorsive quando non c'è modo (o nessuno scopo) di passarli come parametri.
  3. Per memorizzare nella cache il valore che normalmente è meglio recuperare una volta. Ad esempio, risultato della lettura del file immutabile sul server.

Trucchi

La variabile statica esiste solo nell'ambito di una funzione locale. Non è possibile accedervi al di fuori della funzione in cui è stato definito. Quindi si può essere certi che manterrà il suo valore invariato fino alla chiamata successiva a quella funzione.

La variabile statica può essere definita solo come scalare o come espressione scalare (dal PHP 5.6). Assegnare altri valori ad esso porta inevitabilmente a un fallimento almeno nel momento in cui questo articolo è stato scritto. Tuttavia, puoi farlo solo nella riga successiva del tuo codice:

function countSheep($num) {
  static $counter = 0;
  $counter += sqrt($num);//imagine we need to take root of our sheep each time
  echo "$counter sheep jumped over fence";
}

Risultato:

2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence

La funzione statica è un po '"condivisa" tra metodi di oggetti della stessa classe. È facile da capire visualizzando il seguente esempio:

class SomeClass {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$object1 = new SomeClass;
$object2 = new SomeClass;

$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother

Funziona solo con oggetti della stessa classe. Se gli oggetti provengono da classi diverse (anche estendendosi a vicenda) il comportamento delle variabili statiche sarà come previsto.

La variabile statica è l'unico modo per mantenere i valori tra le chiamate a una funzione?

Un altro modo per mantenere i valori tra le chiamate di funzione è utilizzare le chiusure. Le chiusure sono state introdotte in PHP 5.3. In due parole, consentono di limitare l'accesso a un insieme di variabili nell'ambito di una funzione a un'altra funzione anonima che sarà l'unico modo per accedervi. Essere in variabili di chiusura può imitare (più o meno con successo) concetti OOP come "costanti di classe" (se sono stati passati in chiusura per valore) o "proprietà private" (se passati per riferimento) nella programmazione strutturata.

Quest'ultimo in realtà consente di utilizzare chiusure invece di variabili statiche. Cosa usare dipende sempre dallo sviluppatore decidere, ma va detto che le variabili statiche sono sicuramente utili quando si lavora con le ricorsioni e meritano di essere notate dagli sviluppatori.


2

Non invierò una risposta completa alla domanda, poiché quelli esistenti e il manuale di PHP fanno un ottimo lavoro nel spiegare la maggior parte di questo.

Ma un argomento che è stato mancato è stato quello di superglobals , tra cui il comunemente usato $_POST, $_GET, $_SESSION, ecc Queste variabili sono le matrici che sono sempre a disposizione, in ogni ambito, senza una globaldichiarazione.

Ad esempio, questa funzione stamperà il nome dell'utente che esegue lo script PHP. La variabile è disponibile per la funzione senza alcun problema.

<?php
function test() {
    echo $_ENV["user"];
}

La regola generale di "i globuli sono cattivi" è generalmente modificata in PHP in "i globuli sono cattivi, ma i superglobali vanno bene", purché non vengano utilizzati in modo improprio. (Tutte queste variabili sono scrivibili, quindi potrebbero essere utilizzate per evitare l'iniezione di dipendenza se tu fossi davvero terribile.)

Queste variabili non sono garantite per essere presenti; un amministratore può disabilitare alcuni o tutti usando la variables_orderdirettiva in php.ini, ma questo non è un comportamento comune.


Un elenco degli attuali superglobali:

  • $GLOBALS - Tutte le variabili globali nello script corrente
  • $_SERVER - Informazioni sul server e l'ambiente di esecuzione
  • $_GET - Valori passati nella stringa di query dell'URL, indipendentemente dal metodo HTTP utilizzato per la richiesta
  • $_POST- Valori passati in una richiesta POST HTTP con application/x-www-form-urlencodedo multipart/form-datatipi MIME
  • $_FILES- File passati in una richiesta POST HTTP con un multipart/form-datatipo MIME
  • $_COOKIE - Cookie passati con la richiesta corrente
  • $_SESSION - Variabili di sessione memorizzate internamente da PHP
  • $_REQUEST- Tipicamente una combinazione di $_GETe $_POST, ma a volte $_COOKIES. Il contenuto è determinato dalla request_orderdirettiva in php.ini.
  • $_ENV - Le variabili di ambiente dello script corrente
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.