Was ist ein Zitat?
Zitieren in PHP bedeutet, auf denselben Variableninhalt mit unterschiedlichen Namen zuzugreifen. Dies ist kein C-Zeiger; die Referenz ist ein Symboltabellenalias. Beachten Sie, dass in PHP Variablennamen und Variableninhalte unterschiedlich sind, sodass derselbe Inhalt unterschiedliche Namen haben kann. Die engste Analogie sind die Dateinamen von Unix und die Dateien selbst – die Variablennamen sind die Verzeichniseinträge und die Variableninhalte sind die Dateien selbst. Referenzen können als Hardlinks in Unix-Dateisystemen betrachtet werden.
Was bewirkt ein Zitat?
PHP-Referenzen ermöglichen es zwei Variablen, auf denselben Inhalt zu verweisen. Das heißt, dabei gilt:
<?php $a =& $b; ?>
Das bedeutet, dass $a und $b auf dieselbe Variable verweisen.
Hinweis:
$a und $b sind hier genau gleich. Es ist nicht so, dass $a auf $b zeigt oder umgekehrt, sondern dass $a und $b auf die gleiche Stelle zeigen.
Hinweis:
Wenn ein Array mit einer Referenz kopiert wird, wird sein Wert nicht dereferenziert. Das Gleiche gilt für die Übergabe von Array-Werten an Funktionen.
Hinweis:
Wenn eine undefinierte Variable per Referenz zugewiesen, per Referenz übergeben oder per Referenz zurückgegeben wird, wird die Variable automatisch erstellt.
Beispiel #1 Verwendung von Referenzen auf undefinierte Variablen
<?php function foo(&$var) { } foo($a); // $a is "created" and assigned to null $b = array(); foo($b['b']); var_dump(array_key_exists('b', $b)); // bool(true) $c = new StdClass; foo($c->d); var_dump(property_exists($c, 'd')); // bool(true) ?>
Die gleiche Syntax kann in Funktionen, die Referenzen zurückgeben, und im neuen Operator (PHP 4.0.4 und höher) verwendet werden:
<?php $bar =& new fooclass(); $foo =& find_var($bar); ?>
Ab PHP 5 gibt new automatisch eine Referenz zurück, sodass die Verwendung von =& hier veraltet ist und eine Nachricht auf E_STRICT-Ebene erzeugt.
Hinweis:
Wenn der &-Operator nicht verwendet wird, wird eine Kopie des Objekts generiert. Wenn Sie $this in einer Klasse verwenden, gilt es für die aktuelle Instanz dieser Klasse. Eine Zuweisung ohne & kopiert die Instanz (z. B. ein Objekt) und $this wird auf die Kopie angewendet, was nicht immer das gewünschte Ergebnis ist. Aufgrund von Leistungs- und Speicherverbrauchsproblemen möchten Sie normalerweise nur an einer Instanz arbeiten.
Obwohl es möglich ist, etwaige Fehlermeldungen in einem Konstruktor mit dem @-Operator, wie z. B. @new, zu unterdrücken, hat dies keine Auswirkung, wenn eine &new-Anweisung verwendet wird. Dies ist eine Einschränkung der Zend-Engine und führt zu einem Parsing-Fehler.
Warnung
Wenn eine Referenz einer als global deklarierten Variablen innerhalb einer Funktion zugewiesen wird, ist die Referenz nur innerhalb der Funktion sichtbar. Dies kann durch die Verwendung des Arrays $GLOBALS vermieden werden.
Beispiel #2 Referenzieren globaler Variablen innerhalb einer Funktion
<?php $var1 = "Example variable"; $var2 = ""; function global_references($use_globals) { global $var1, $var2; if (!$use_globals) { $var2 =& $var1; // visible only inside the function } else { $GLOBALS["var2"] =& $var1; // visible also in global context } } global_references(false); echo "var2 is set to '$var2'\n"; // var2 is set to '' global_references(true); echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable' ?>
Stellen Sie sich global $var; als Abkürzung für $var =& $GLOBALS['var']; vor. Wenn Sie also $var eine weitere Referenz zuweisen, ändert sich nur die Referenz auf die lokale Variable.
Hinweis:
Wenn einer Variablen mit Referenz in einer foreach-Anweisung ein Wert zugewiesen wird, wird auch das referenzierte Objekt geändert.
Beispiel #3 Zitat und foreach-Anweisung
<?php $ref = 0; $row =& $ref; foreach (array(1, 2, 3) as $row) { // do something } echo $ref; // 3 - last element of the iterated array ?>
Das zweite, was eine Referenz bewirkt, ist die Übergabe einer Variablen als Referenz. Dies wird erreicht, indem eine lokale Variable innerhalb der Funktion erstellt wird und diese Variable auf denselben Inhalt im aufrufenden Bereich verweist. Zum Beispiel:
<?php function foo(&$var) { $var++; } $a=5; foo($a); ?>
wird $a in 6 ändern. Dies liegt daran, dass in der Funktion foo die Variable $var auf dasselbe zeigt wie $a. Eine ausführlichere Erklärung finden Sie unter „Übergabe als Referenz“.
Die dritte Funktion einer Referenz ist die Referenzrückgabe.
Was Zitate nicht sind
Wie bereits erwähnt, sind Referenzen keine Hinweise. Dies bedeutet, dass die folgende Struktur nicht den erwarteten Effekt erzielt:
<?php function foo(&$var) { $var =& $GLOBALS["baz"]; } foo($bar); ?>
Dies führt dazu, dass die Variable $var in der Funktion foo an $bar gebunden wird, wenn die Funktion aufgerufen wird, dann aber erneut an $GLOBALS["baz"] gebunden wird. Es ist nicht möglich, $bar über den Referenzmechanismus an eine andere Variable innerhalb des Funktionsaufrufbereichs zu binden, da es in der Funktion foo keine Variable $bar gibt (sie wird als $var dargestellt, aber $var hat nur den Variableninhalt und keinen Aufruf Name-Wert-Bindung der Symboltabelle). Sie können Referenzrückgaben auf Referenzvariablen verwenden, die von der Funktion ausgewählt wurden.
Übergabe als Referenz
Sie können eine Variable als Referenz an eine Funktion übergeben, sodass die Funktion den Wert ihres Arguments ändern kann. Die Syntax lautet wie folgt:
<?php function foo(&$var) { $var++; } $a=5; foo($a); // $a is 6 here ?>
Beachten Sie, dass es in Funktionsaufrufen keine Referenzsymbole gibt – nur in Funktionsdefinitionen. Die Funktionsdefinition allein reicht aus, damit Parameter korrekt per Referenz übergeben werden. Wenn Sie in neueren PHP-Versionen & in foo(&$a); verwenden, erhalten Sie eine Warnung, dass „Call-time pass-by-reference“ veraltet ist.
Folgendes kann als Referenz übergeben werden:
Variable wie foo($a)
Neue Anweisung, wie zum Beispiel foo(new foobar())
Eine von einer Funktion zurückgegebene Referenz, zum Beispiel:
<?php function &bar() { $a = 5; return $a; } foo(bar()); ?>
Ausführliche Erläuterungen finden Sie in der Referenzrückgabe.
Andere Ausdrücke können nicht als Referenz übergeben werden und das Ergebnis ist undefiniert. Das folgende Beispiel für die Referenzübergabe ist beispielsweise ungültig:
<?php function bar() // Note the missing & { $a = 5; return $a; } foo(bar()); // 自 PHP 5.0.5 起导致致命错误 foo($a = 5) // 表达式,不是变量 foo(5) // 导致致命错误 ?>
Diese Bedingungen sind in PHP 4.0.4 und späteren Versionen verfügbar.
Rückgabe per Referenz
Die Referenzrückgabe wird verwendet, wenn Sie mithilfe einer Funktion herausfinden möchten, an welche Variable die Referenz gebunden werden soll. Verwenden Sie keine Rückgabereferenzen, um die Leistung zu steigern. Die Engine ist intelligent genug, um sie selbst zu optimieren. Geben Sie Referenzen nur zurück, wenn ein triftiger technischer Grund vorliegt! Um eine Referenz zurückzugeben, verwenden Sie diese Syntax:
<?php class foo { public $value = 42; public function &getValue() { return $this->value; } } $obj = new foo; $myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42. $obj->value = 2; echo $myValue; // prints the new value of $obj->value, i.e. 2. ?>
本例中 getValue 函数所返回的对象的属性将被赋值,而不是拷贝,就和没有用引用语法一样。
Note: 和参数传递不同,这里必须在两个地方都用 & 符号——指出返回的是一个引用,而不是通常的一个拷贝,同样也指出 $myValue 是作为引用的绑定,而不是通常的赋值。
Note: 如果试图这样从函数返回引用:return ($this->value);,这将不会起作用,因为在试图返回一个表达式的结果而不是一个引用的变量。只能从函数返回引用变量——没别的方法。如果代码试图返回一个动态表达式或 new 运算符的结果,自 PHP 4.4.0 和 PHP 5.1.0 起会发出一条 E_NOTICE 错误。
<?php function &test(){ static $b=0;//申明一个静态变量 $b=$b+1; echo $b; return $b; } $a=test();//这条语句会输出$b的值为1 $a=5; $a=test();//这条语句会输出$b的值为2 $a=&test();//这条语句会输出$b的值为3 $a=5; $a=test();//这条语句会输出$b的值为6 ?>
$a=test()方式调用函数,只是将函数的值赋给$a而已,而$a做任何改变化,都不会影响到函数中的$b,而通过$a=&test()方式调用函数呢, 他的作用是将return $b中的$b变量的内存地址与$a变量的内存地址指向了同一个地方,即产生了相当于这样的效果($a=&b;) 所以改变$a的值,也同时改变了$b的值,所以在执行了 $a=&test(); $a=5; 以后,$b的值变为了5。
取消引用
当 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。例如:
<?php $a = 1; $b =& $a; unset($a); ?>
不会 unset $b,只是 $a。
再拿这个和 Unix 的 unlink 调用来类比一下可能有助于理解。
引用定位
许多 PHP 的语法结构是通过引用机制实现的,所以上述有关引用绑定的一切也都适用于这些结构。一些结构,例如引用传递和返回,已经在上面提到了。其它使用引用的结构有:
global 引用
当用 global $var 声明一个变量时实际上建立了一个到全局变量的引用。也就是说和这样做是相同的:
<?php $var =& $GLOBALS["var"]; ?>
这意味着,例如,unset $var 不会 unset 全局变量。
使用unset($a)与$a=null的结果是不一样的。如果该块内存只有$a一个映射,那么unset($a)与$a=null等价,该内存的引用计数变为0,被自动回收;如果该块内存有$a和$b两个映射,那么unset($a)将导致$a=null且$b不变的情况,而$a=null会导致$a=$b=null的情况。
原因:某变量赋值为null,将导致该变量对应的内存块的引用计数直接置为0,被自动回收。
$this
在一个对象的方法中,$this 永远是调用它的对象的引用。
引用的作用
如果程序比较大,引用同一个对象的变量比较多,并且希望用完该对象后手工清除它,个人建议用 "&" 方式,然后用$var=null的方式清除. 其它时候还是用php5的默认方式吧. 另外, php5中对于大数组的传递,建议用 "&" 方式, 毕竟节省内存空间使用。
下面再来个小插曲 php中对于地址的指向(类似指针)功能不是由用户自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝”的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会被拷贝的。
通俗的讲
1:如果有下面的代码
<?ph $a="ABC"; $b=$a; ?>
其实此时,$a与$b都是指向同一内存地址,而并不是$a与$b占用不同的内存。
2:如果在上面的代码基础上再加上如下代码
$a="EFG";
由于$a与$b所指向的内存的数据要重新写一次了,此时Zend核心会自动判断 自动为$b生产一个$a的数据拷贝,重新申请一块内存进行存储。