1. Erläuterungen
Wird der Geltungsbereich (Scope) einer Funktion verlassen, dann gehen gewöhnlich auch alle innerhalb dieser Funktion definierten Variablen verloren. Beim nächsten Aufruf der Funktion müssen daher alle lokalen Variablen erneut definiert werden. Mitunter ist dies aber nicht erwünscht, zum Beispiel wenn rechenintensive Aufgaben nur ein mal durchgeführt und danach zwischengespeichert werden sollen. Um zu erreichen, dass bestimmte lokale Variablen über mehrere Aufrufe einer Funktion hinweg ihre Werte behalten, können diese als „static” markiert werden. Nach dem Ende der Funktion sind diese zwar nicht außerhalb des Geltungsbereichs der Funktion verfügbar, bei ihrem nächsten Aufruf kann allerdings wieder innerhalb der Funktion auf sie zugegriffen werden — so als wäre die Funktion nicht beendet worden, sondern würde einfach sofort wieder am Anfang beginnen.
2. Einfaches Beispiel mit einer statischen Variable und echo
Im nachfolgenden Beispiel „überlebt” die statische Variable $x das Ende der Funktion.
<?php function echoStatic() { // statische Variable $x definieren // Wichtig: Das wird nur ein mal ausgefuehrt, die Variable wird also NICHT bei // jedem Funktionsaufruf wieder auf 0 gesetzt static $x = 0; echo("$x\n"); // ausgeben $x++; // um 1 erhoehen } echoStatic(); echoStatic(); echoStatic(); ?>
0 1 2
3. Kein Zugriff von "außerhalb"
Auf die statischen Variablen einer Funktion kann nicht von außerhalb des Geltungsbereichs zugegriffen werden. Sie sind nur innerhalb der Funktion verfügbar.
<?php function echoStatic() { static $x = 0; $x = 100; echo("$x\n"); } echoStatic(); // erzeugt einen Fehler, da $x nur in echoStatic() verfuegbar ist var_dump($x); ?>
100 <br /> <b>Notice</b>: Undefined variable: x in <b>...\test.php</b> on line <b>10</b><br /> NULL
4. Static-Keyword muss bei jedem Aufruf verwendet werden
Das „static”-Keyword darf zwar prinzipiell überall in der Funktion stehen, muss aber immer vor dem ersten Zugriff auf die Variable platziert werden. Andernfalls kann die Variable falsche Werte enthalten oder komplett fehlen. Im nächsten Beispiel wird das „static”-Keyword nur beim ersten Aufruf der Funktion verwendet, danach nicht mehr. Das Ergebnis ist, dass sich PHP ab dem zweiten Aufruf darüber beklagt, dass $x nicht definiert wurde.
<?php $GLOBALS['called'] = false; function echoStatic() { if (!$GLOBALS['called']) { static $x = 0; $GLOBALS['called'] = true; } echo("$x\n"); $x++; } echoStatic(); echoStatic(); ?>
0 <br /> <b>Notice</b>: Undefined variable: x in <b>...\test.php</b> on line <b>10</b><br /> <br /> <b>Notice</b>: Undefined variable: x in <b>...\test.php</b> on line <b>11</b><br />
Das wirft nun die Frage auf, was passiert, wenn man eine Variable bei manchen Funktionsaufrufen als statisch markiert und bei manchen als „normale” lokale Variable verwendet. Wie das nachfolgende Beispiel zeigt, geht die statische Variable dadurch nicht verloren.
<?php $GLOBALS['calls'] = 0; function echoStatic() { // $x bei jedem zweiten Aufruf als statisch markieren if ($GLOBALS['calls'] % 2 === 0) { static $x = 0; } else { $x = 0; } $GLOBALS['calls']++; echo("$x\n"); $x++; } echoStatic(); echoStatic(); echoStatic(); echoStatic(); echoStatic(); echoStatic(); ?>
0 0 1 0 2 0
Weiterhin mag man sich fragen, zu welchen Verhalten es führt, innerhalb eines Funktionsaufrufs zuerst eine lokale Variable zu definieren und danach diese als statisch zu markieren. Im nächsten Beispiel wird dies probiert und wie sich herausstellt, wechselt die Variable mit Verwendung des „static”-Keywords wieder auf ihren statischen Wert:
<?php $GLOBALS['calls'] = 0; function echoStatic() { // zuerst lokale Variable mit Namen $x definieren $x = 0; echo("$x\n"); // danach statische Variable mit gleichen Namen definieren static $x = 0; echo("$x\n"); $x++; } echoStatic(); echoStatic(); echoStatic(); echoStatic(); ?>
0 0 0 1 0 2 0 3
5. Zwischenspeichern mit statischen Variablen
Das nächste Beispiel zeigt, wie statische Variablen zur Performance-Steigerung eingesetzt werden können indem Ergebnisse nur ein Mal generiert werden. Dazu wird eine Funktion definiert, die alle Dateien in einem übergebenen Verzeichnis auflistet. Die Funktion greift aber nur beim ersten Mal tatsächlich auf das Verzeichnis zu. Bei allen weiteren Aufrufen liest sie das Ergebnis aus der Variable $files aus. So muss nur ein Mal das Verzeichnis durchsucht werden. Der Nachteil ist, dass alle Änderungen nach dem ersten Aufruf nicht erkannt werden, was zu unerwarteten und schwer zu identifizierenden Bugs führen kann.
<?php function getFilesInDir($dir) { static $files = array(); // Falls das Verzeichnis bereits durchsucht wurde, wird das Ergebnis erneut zurückgegeben if (isset($files[$dir])) { return $files[$dir]; } else { $files[$dir] = array(); } // Dieses echo wird nur beim ersten Durchsuchen des Verzeichnisses erzeugt echo("Debug: Lese Dateien aus $dir\n"); // Dateien auslesen $handle = opendir($dir); while ($file = readdir($handle)) { $files[$dir][] = $file; } closedir($handle); return $files[$dir]; } // erster Aufruf, echo wird ausgegeben var_dump(getFilesInDir('./')); // zweiter Aufruf, echo wird nicht ausgegeben, da das zwischengespeicherte Ergebnis zurueckgegeben wird var_dump(getFilesInDir('./')); ?>
Debug: Lese Dateien aus ./ array(9) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(11) "Example.php" [3]=> string(14) "HelloWorld.php" [4]=> string(14) "myfunction.php" [5]=> string(13) "nametest1.php" [6]=> string(13) "nametest2.php" [7]=> string(10) "readme.txt" [8]=> string(8) "test.php" } array(9) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(11) "Example.php" [3]=> string(14) "HelloWorld.php" [4]=> string(14) "myfunction.php" [5]=> string(13) "nametest1.php" [6]=> string(13) "nametest2.php" [7]=> string(10) "readme.txt" [8]=> string(8) "test.php" }