Qu'est-ce qu'une citation
Citer en PHP signifie accéder au même contenu de variable avec des noms différents. Ce n'est pas comme un pointeur C, la référence est un alias de table de symboles. Notez qu'en PHP, les noms de variables et le contenu des variables sont différents, donc le même contenu peut avoir des noms différents. L'analogie la plus proche concerne les noms de fichiers Unix et les fichiers eux-mêmes : les noms de variables sont les entrées du répertoire et le contenu des variables est les fichiers eux-mêmes. Les références peuvent être considérées comme des liens physiques dans les systèmes de fichiers Unix.
À quoi sert un devis
Les références PHP permettent à deux variables de pointer vers le même contenu. Cela signifie, en faisant cela :
<?php $a =& $b; ?>
Cela signifie que $a et $b pointent vers la même variable.
Remarque :
$a et $b sont exactement les mêmes ici. Ce n'est pas que $a pointe vers $b ou vice versa, mais que $a et $b pointent vers le même endroit.
Remarque :
Si un tableau avec une référence est copié, sa valeur ne sera pas déréférencée. Il en va de même pour transmettre des valeurs de tableau aux fonctions.
Remarque :
Si une variable non définie est affectée par référence, passée par référence ou renvoyée par référence, la variable sera automatiquement créée.
Exemple n°1 Utilisation de références à des variables non définies
<?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) ?>
La même syntaxe peut être utilisée dans les fonctions, qui renvoient des références, et dans l'opérateur new (PHP 4.0.4 et versions ultérieures) :
<?php $bar =& new fooclass(); $foo =& find_var($bar); ?>
Depuis PHP 5, new renvoie automatiquement une référence, donc utiliser =& ici est obsolète et produit un message de niveau E_STRICT.
Remarque :
Ne pas utiliser l'opérateur & entraîne la génération d'une copie de l'objet. Si vous utilisez $this dans une classe, cela s'appliquera à l'instance actuelle de cette classe. L'affectation sans & copiera l'instance (par exemple un objet) et $this sera appliqué à la copie, ce qui n'est pas toujours le résultat souhaité. En raison de problèmes de performances et de consommation de mémoire, vous ne souhaitez généralement travailler que sur une seule instance.
Bien qu'il soit possible de supprimer tout message d'erreur dans un constructeur à l'aide de l'opérateur @, tel que @new, cela n'a aucun effet lors de l'utilisation d'une instruction &new. Il s'agit d'une limitation du moteur Zend et entraînera une erreur d'analyse.
Attention
Si une référence est affectée à une variable déclarée globale à l'intérieur d'une fonction, la référence n'est visible qu'à l'intérieur de la fonction. Cela peut être évité en utilisant le tableau $GLOBALS.
Exemple #2 Référencer des variables globales dans une fonction
<?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' ?>
Pensez à global $var; comme un raccourci pour $var =& $GLOBALS['var'];. Ainsi, attribuer une autre référence à $var ne modifie que la référence à la variable locale.
Remarque :
Si une variable avec une référence se voit attribuer une valeur dans une instruction foreach, l'objet référencé est également modifié.
Exemple n°3 Citation et instruction foreach
<?php $ref = 0; $row =& $ref; foreach (array(1, 2, 3) as $row) { // do something } echo $ref; // 3 - last element of the iterated array ?>
La deuxième chose qu'une référence fait est de transmettre une variable par référence. Ceci est accompli en créant une variable locale dans la fonction et cette variable fait référence au même contenu dans la portée appelante. Par exemple :
<?php function foo(&$var) { $var++; } $a=5; foo($a); ?>
changera $a en 6. En effet, dans la fonction foo, la variable $var pointe vers la même chose que $a. Voir Passage par référence pour une explication plus détaillée.
La troisième chose qu'une référence fait est le retour de référence.
Quelles citations ne le sont pas
Comme mentionné précédemment, les références ne sont pas des pointeurs. Cela signifie que la structure suivante ne produira pas l'effet escompté :
<?php function foo(&$var) { $var =& $GLOBALS["baz"]; } foo($bar); ?>
Cela fera que la variable $var dans la fonction foo sera liée à $bar lorsque la fonction est appelée, mais ensuite liée à $GLOBALS["baz"]. Il n'est pas possible de lier $bar à une autre variable dans la portée de l'appel de fonction via le mécanisme de référence, car il n'y a pas de variable $bar dans la fonction foo (elle est représentée par $var, mais $var n'a que le contenu de la variable et aucun appel liaison nom-valeur de la table de symboles). Vous pouvez utiliser des retours de référence pour référencer les variables sélectionnées par la fonction.
Passez par référence
Vous pouvez passer une variable par référence à une fonction afin que la fonction puisse modifier la valeur de son argument. La syntaxe est la suivante :
<?php function foo(&$var) { $var++; } $a=5; foo($a); // $a is 6 here ?>
Notez qu'il n'y a pas de symboles de référence dans les appels de fonction - uniquement dans les définitions de fonction. La définition de la fonction à elle seule suffit pour que les paramètres soient passés correctement par référence. Dans les versions récentes de PHP, si vous utilisez & in foo(&$a); vous recevrez un avertissement indiquant que "Call-time pass-by-reference" est obsolète.
Les éléments suivants peuvent être transmis par référence :
Variable, telle que foo($a)
Nouvelle instruction, telle que foo(new foobar())
Une référence renvoyée par une fonction, par exemple :
<?php function &bar() { $a = 5; return $a; } foo(bar()); ?>
Pour une explication détaillée, voir le retour de référence.
Aucune autre expression ne peut être transmise par référence et le résultat n'est pas défini. Par exemple, l'exemple suivant de passage par référence n'est pas valide :
<?php function bar() // Note the missing & { $a = 5; return $a; } foo(bar()); // 自 PHP 5.0.5 起导致致命错误 foo($a = 5) // 表达式,不是变量 foo(5) // 导致致命错误 ?>
Ces conditions sont disponibles en PHP 4.0.4 et versions ultérieures.
Retour par référence
Le retour de référence est utilisé lorsque vous souhaitez utiliser une fonction pour trouver à quelle variable la référence doit être liée. N'utilisez pas de références de retour pour augmenter les performances, le moteur est suffisamment intelligent pour l'optimiser lui-même. Ne renvoyez les références que s’il existe une raison technique valable ! Pour renvoyer une référence, utilisez cette syntaxe :
<?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的数据拷贝,重新申请一块内存进行存储。