Referenz: Was ist der Variablenbereich, auf welche Variablen kann von wo aus zugegriffen werden und was sind "undefinierte Variablen" -Fehler?

167

Hinweis: Dies ist eine Referenzfrage zum Umgang mit dem variablen Bereich in PHP. Bitte schließen Sie eine der vielen Fragen, die zu diesem Muster passen, als Duplikat dieser Frage.

Was ist "variabler Bereich" in PHP? Sind Variablen aus einer .php-Datei in einer anderen zugänglich? Warum erhalte ich manchmal Fehler "undefinierte Variable" ?

täuschen
quelle
1
Wenn Sie dies als "Undefinierte Variable" betitelt haben, erhalten Sie viele weitere Treffer :) Gute Arbeit
Dale
@ Dale, eigentlich nein. 2k Ansichten in 2 Jahren ist ....
Pacerier
7
@Pacerier ... über den richtigen Zeitpunkt, um einen zufälligen Kommentar zu hinterlassen?
Dale
@ Pacerier Ich bin mir aber auch nicht sicher, was du mit diesem Kommentar sagen willst. "Ist ..." ... was?! : P
Täuschung
@Dale, jetzt ist der richtige Zeitpunkt: Wow, obwohl die Frage 2 Jahre lang stagnierte, nachdem das Wort " zustandslos " zu GoogleDex hinzugefügt wurde, hat sich die Trefferquote in nur 6 Monaten buchstäblich verdreifacht.
Pacerier

Antworten:

188

Was ist "variabler Bereich"?

Variablen haben einen begrenzten "Umfang" oder "Orte, von denen aus sie zugänglich sind". Nur weil Sie schrieb $foo = 'bar';einmal irgendwo in der Anwendung bedeutet nicht , dass Sie sich beziehen können $foovon überall sonst in der Anwendung. Die Variable $foohat einen bestimmten Bereich, in dem sie gültig ist, und nur Code im selben Bereich hat Zugriff auf die Variable.

Wie ist ein Bereich in PHP definiert?

Sehr einfach: PHP hat Funktionsumfang . Dies ist die einzige Art von Bereichstrennzeichen, die in PHP vorhanden ist. Variablen innerhalb einer Funktion sind nur innerhalb dieser Funktion verfügbar. Variablen außerhalb von Funktionen sind überall außerhalb von Funktionen verfügbar, jedoch nicht innerhalb einer Funktion. Dies bedeutet, dass es in PHP einen speziellen Bereich gibt: den globalen Bereich. Jede außerhalb einer Funktion deklarierte Variable liegt in diesem globalen Bereich.

Beispiel:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$foobefindet sich im globalen Bereich, $bazbefindet sich in einem lokalen Bereich innerhalb myFunc. Nur Code im Inneren myFunchat Zugriff auf $baz. Nur Code außerhalb myFunc hat Zugriff auf $foo. Keiner hat Zugang zum anderen:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

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

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

Umfang und enthaltene Dateien

Dateigrenzen trennen den Bereich nicht:

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

Für included-Code gelten dieselben Regeln wie für jeden anderen Code: nur der functionseparate Bereich. Zum Zwecke des Gültigkeitsbereichs können Sie Dateien wie das Kopieren und Einfügen von Code einschließen:

c.php

<?php

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

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

Im obigen Beispiel a.phpwurde darin enthalten myFunc, dass alle darin enthaltenen Variablen a.phpnur einen lokalen Funktionsumfang haben. Nur weil sie im globalen Bereich zu sein scheinen , a.phpheißt das nicht unbedingt, dass sie es sind, sondern es hängt tatsächlich davon ab, in welchem ​​Kontext dieser Code enthalten ist / ausgeführt wird.

Was ist mit Funktionen innerhalb von Funktionen und Klassen?

Jede neue functionErklärung führt einen neuen Geltungsbereich ein, so einfach ist das.

(anonyme) Funktionen innerhalb von Funktionen

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

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

    // no access to $baz
}

Klassen

$foo = 'foo';

class Bar {

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

}

// no access to $baz

Wofür ist der Umfang gut?

Der Umgang mit Scoping-Problemen mag ärgerlich erscheinen, aber ein begrenzter variabler Umfang ist für das Schreiben komplexer Anwendungen unerlässlich! Wenn jede von Ihnen deklarierte Variable von überall in Ihrer Anwendung verfügbar wäre, würden Sie Ihre Variablen schrittweise durchlaufen, ohne wirklich nachverfolgen zu können, was was ändert. Es gibt nur so viele sinnvolle Namen, die Sie Ihren Variablen geben können, dass Sie die Variable " $name" wahrscheinlich an mehr als einer Stelle verwenden möchten . Wenn Sie diesen eindeutigen Variablennamen nur einmal in Ihrer App haben könnten, müssten Sie auf wirklich komplizierte Benennungsschemata zurückgreifen, um sicherzustellen, dass Ihre Variablen eindeutig sind und Sie nicht die falsche Variable aus dem falschen Code ändern.

Beobachten:

function foo() {
    echo $bar;
}

Was würde die obige Funktion tun, wenn es keinen Bereich gäbe? Woher kommt $bardas? Welchen Zustand hat es? Ist es überhaupt initialisiert? Müssen Sie jedes Mal überprüfen? Dies ist nicht wartbar. Was uns zu ...

Bereichsgrenzen überschreiten

Der richtige Weg: Variablen ein- und ausgeben

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

Die Variable $barkommt explizit als Funktionsargument in diesen Bereich. Wenn man sich diese Funktion ansieht, ist klar, woher die Werte stammen, mit denen sie arbeitet. Es dann explizit zurückgibt einen Wert. Der Aufrufer hat das Vertrauen zu wissen, mit welchen Variablen die Funktion arbeitet und woher ihre Rückgabewerte stammen:

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

Erweiterung des Variablenbereichs auf anonyme Funktionen

$foo = 'bar';

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

$baz();

Die anonyme Funktion schließt explizit $fooaus ihrem umgebenden Bereich ein. Beachten Sie, dass dies nicht mit dem globalen Bereich identisch ist .

Der falsche Weg: global

Wie bereits erwähnt, ist der globale Bereich etwas Besonderes, und Funktionen können explizit Variablen daraus importieren:

$foo = 'bar';

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

Diese Funktion verwendet und ändert die globale Variable $foo. Mach das nicht! (Es sei denn, Sie wissen wirklich wirklich wirklich wirklich, was Sie tun, und selbst dann: nicht!)

Der Aufrufer dieser Funktion sieht lediglich Folgendes:

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

Es gibt keinen Hinweis darauf, dass diese Funktion Nebenwirkungen hat , dies ist jedoch der Fall. Dies wird sehr leicht zu einem Durcheinander, da einige Funktionen ständig geändert werden und einen globalen Status erfordern . Sie möchten, dass Funktionen zustandslos sind , nur auf ihre Eingaben reagieren und definierte Ausgaben zurückgeben, wie oft Sie sie auch aufrufen.

Sie sollten es vermeiden, den globalen Bereich so weit wie möglich zu verwenden. Mit Sicherheit sollten Sie keine Variablen aus dem globalen Bereich in einen lokalen Bereich "ziehen".

täuschen
quelle
Sie haben gerade den falschen Weg fürglobal gesagt , also sagen Sie uns bitte, wann wir verwenden sollen global. Und bitte erklären Sie (ein bisschen) was ist static..?
@stack Es gibt keinen "richtigen" Weg für global. Es ist immer falsch. Das Übergeben von Funktionsparametern ist richtig. staticwird im Handbuch gut erklärt und hat nicht viel mit Umfang zu tun. Kurz gesagt, es kann als "globale Variable mit Gültigkeitsbereich" betrachtet werden. Ich werde die Verwendung hier kunststube.net/static etwas erweitern .
Täuschung
Mein einfacher Gedanke ist, wenn eine PHP-Variable wichtig genug ist, um einen globalen Status zu verdienen, verdient sie eine Spalte in einer Datenbank. Vielleicht ist es ein Overkill, aber es ist ein narrensicherer Ansatz, der zu meinem mittelmäßigen Programmierwitz passt
Arthur Tarasov
@Arthur Dort gibt es so viel zu entpacken… ಠ_ಠ Dies ist mit Sicherheit kein Ansatz, den ich unterstützen würde.
Täuschung
@deceze wee ein bisschen ein Argument, das heute hier passiert stackoverflow.com/q/51409392 - wo das OP erwähnt, dass das Duplikat (hier) nichts erwähnt include_onceund möglicherweise require_onceauch irgendwo hinzugefügt werden sollte; nur sagen. OP stimmte dafür, ihre Frage ebenfalls erneut zu eröffnen. Wäre ihr Beitrag ein Sonderfall und was sollte dagegen getan werden?
Funk Forty Niner
10

Obwohl auf Variablen, die innerhalb des Funktionsumfangs einer Funktion definiert sind, nicht von außen zugegriffen werden kann, bedeutet dies nicht, dass Sie ihre Werte nach Abschluss dieser Funktion nicht mehr verwenden können. PHP hat ein bekanntes staticSchlüsselwort, das in objektorientiertem PHP häufig zum Definieren statischer Methoden und Eigenschaften verwendet wird. Man sollte jedoch berücksichtigen, dass statices auch in Funktionen zum Definieren statischer Variablen verwendet werden kann.

Was ist es 'statische Variable'?

Die statische Variable unterscheidet sich von der im Funktionsumfang definierten gewöhnlichen Variablen für den Fall, dass sie keinen Wert verliert, wenn die Programmausführung diesen Bereich verlässt. Betrachten wir das folgende Beispiel für die Verwendung statischer Variablen:

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

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

Ergebnis:

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

Wenn wir $counterohne definiert hätten, wäre staticjedes Mal der Echo-Wert der gleiche wie der $numan die Funktion übergebene Parameter. Mit statickönnen Sie diesen einfachen Zähler ohne zusätzliche Problemumgehung erstellen.

Anwendungsfälle für statische Variablen

  1. Speichern von Werten zwischen aufeinanderfolgenden Funktionsaufrufen.
  2. Speichern von Werten zwischen rekursiven Aufrufen, wenn es keine Möglichkeit (oder keinen Zweck) gibt, sie als Parameter zu übergeben.
  3. Zum Zwischenspeichern von Werten, die normalerweise besser einmal abgerufen werden können. Zum Beispiel das Ergebnis des Lesens unveränderlicher Dateien auf dem Server.

Tricks

Statische Variable existiert nur in einem lokalen Funktionsbereich. Außerhalb der Funktion, in der es definiert wurde, kann nicht darauf zugegriffen werden. Sie können also sicher sein, dass der Wert bis zum nächsten Aufruf dieser Funktion unverändert bleibt.

Statische Variablen können nur als Skalar oder als Skalarausdruck definiert werden (seit PHP 5.6). Das Zuweisen anderer Werte führt unweigerlich zu einem Fehler, zumindest zu dem Zeitpunkt, als dieser Artikel geschrieben wurde. Sie können dies jedoch nur in der nächsten Zeile Ihres Codes tun:

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";
}

Ergebnis:

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

Die statische Funktion wird von Methoden von Objekten derselben Klasse gemeinsam genutzt. Das folgende Beispiel ist leicht zu verstehen:

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

Dies funktioniert nur mit Objekten derselben Klasse. Wenn Objekte aus verschiedenen Klassen stammen (sich sogar gegenseitig erweitern), ist das Verhalten statischer Variablen wie erwartet.

Ist eine statische Variable die einzige Möglichkeit, Werte zwischen Aufrufen einer Funktion beizubehalten?

Eine andere Möglichkeit, Werte zwischen Funktionsaufrufen beizubehalten, ist die Verwendung von Verschlüssen. Verschlüsse wurden in PHP 5.3 eingeführt. Mit zwei Worten, Sie können den Zugriff auf einige Variablen innerhalb eines Funktionsumfangs auf eine andere anonyme Funktion beschränken, die der einzige Weg ist, auf sie zuzugreifen. In Abschlussvariablen zu sein, kann OOP-Konzepte wie 'Klassenkonstanten' (wenn sie als Wert geschlossen wurden) oder 'private Eigenschaften' (wenn sie als Referenz übergeben werden) in der strukturierten Programmierung imitieren (mehr oder weniger erfolgreich).

Letzteres erlaubt tatsächlich die Verwendung von Verschlüssen anstelle von statischen Variablen. Es ist immer Sache des Entwicklers, zu entscheiden, was verwendet werden soll. Es sollte jedoch erwähnt werden, dass statische Variablen bei der Arbeit mit Rekursionen auf jeden Fall nützlich sind und es verdienen, von Entwicklern bemerkt zu werden.

Alex Myznikov
quelle
2

Ich werde keine vollständige Antwort auf die Frage veröffentlichen, da die vorhandenen und das PHP-Handbuch das meiste davon hervorragend erklären.

Aber ein Thema , das vermisst wurde , war , dass der Superglobals , einschließlich der häufig verwendeten $_POST, $_GET, $_SESSIONusw. Diese Variablen sind Arrays , die immer zur Verfügung stehen, in jedem Bereich, ohne eine globalErklärung.

Diese Funktion druckt beispielsweise den Namen des Benutzers aus, der das PHP-Skript ausführt. Die Variable steht der Funktion problemlos zur Verfügung.

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

Die allgemeine Regel "Globale sind schlecht" wird in PHP normalerweise in "Globale sind schlecht, aber Superglobale sind in Ordnung" geändert, solange man sie nicht missbraucht. (Alle diese Variablen sind beschreibbar, sodass sie verwendet werden können, um eine Abhängigkeitsinjektion zu vermeiden, wenn Sie wirklich schrecklich waren.)

Es ist nicht garantiert, dass diese Variablen vorhanden sind. Ein Administrator kann einige oder alle mithilfe der variables_orderAnweisung in deaktivieren. php.iniDies ist jedoch kein allgemeines Verhalten.


Eine Liste der aktuellen Superglobalen:

  • $GLOBALS - Alle globalen Variablen im aktuellen Skript
  • $_SERVER - Informationen zum Server und zur Ausführungsumgebung
  • $_GET - In der Abfragezeichenfolge der URL übergebene Werte, unabhängig von der für die Anforderung verwendeten HTTP-Methode
  • $_POST- Werte, die in einer HTTP-POST-Anforderung mit application/x-www-form-urlencodedoder multipart/form-dataMIME-Typen übergeben wurden
  • $_FILES- Dateien, die in einer HTTP-POST-Anforderung mit einem multipart/form-dataMIME-Typ übergeben wurden
  • $_COOKIE - Cookies wurden mit der aktuellen Anfrage übergeben
  • $_SESSION - Von PHP intern gespeicherte Sitzungsvariablen
  • $_REQUEST- Typischerweise eine Kombination von $_GETund $_POST, aber manchmal $_COOKIES. Der Inhalt wird durch die request_orderRichtlinie in bestimmt php.ini.
  • $_ENV - Die Umgebungsvariablen des aktuellen Skripts
miken32
quelle