一、概述
在php中,引用意味着用不同的symbol指向同一个变量内容。它的大致语法是:
symbol_a =& symbol_b
它的正确解读方法是:把symbol_a的指向改变成指向symbol_b指向的结果上。
示例:
$a = 1; $b =& $a; $a = 2; var_dump($b);//output 2
在php结果的数据结构中,每个结果都有一个指向字段,表明这个结果被多少个symbol指向;
示例中表达式『$a = 1』中,编译器会创建一个symbol和一个结果,这个结果只有一个symbol指向它,是刚创建的『$a』;
接下来表达式『$b =& $a』则只创建了一个symbol『$b』,这个symbol和『$a』一样,共同指向了一个结果;
引用的操作将symbol『$b』与symbol『$a』指向了同一个结果,当结果增加一个指向,那么它的指向字段就会加1,相反,unset()一个symbol会导致结果的指向字段减1,直到结果的指向字段为0,CG将其清除;
这种操作有点类似于Unix的文件系统;
二、和C语言的寻址运算符的差别
c语言的变量可以用来保存一个地址值,『&』则作为寻址运算符,在变量前面加『&』的语义是求该变量的内存地址,然后赋值到另一个变量上,通过间接运算符『*』去读取地址指向的内容;
在c语言中,『&』是单独的语义;
而php则不是,根据『&』号出现的位置,有不同的解读,在下述表格先列出可以出现『&』号的位置,稍后小结会对某些结合了『&』的语句进行单独解读;
表达式 | 语义 |
$foo =& $bar | 改变foo的引用至bar的引用 |
function foo(&$bar){} | 改变$bar的引用至外部参数的引用 |
function &foo(){return a;} | 返回a的引用 |
看看这个例子:
<?php function foo(&$var) { $var =& $GLOBALS["baz"]; } foo($bar); ?>
如果按照c语言的思维去理解,它本应该会是这样的:
- 假设函数外部『$bar』是一个指针变量;
- 进入foo()环境,『$var』变量被创建;
- 『$var』被赋值为指向外部变量『$bar』的地址,函数内部把『$baz』的地址赋值给这个地址;
- 『$bar』指向的内容被改变了,换成了指向外部『$baz』的值;
而php是这样做的:
- 进入foo()环境,『$var』symbol被创建;
- 由于在函数参数声明中带有『&』运算符,所以symbol『$var』在创建后马上把指向改为跟『$bar』指向相同的一个值,『$bar』的值引用次数加1;
- 紧接着symbol『$var』的指向再次被表达式『$var =& $GLOBALS["BAZ"]』改变为指向指向外部『$baz』的值,『$baz』的值引用次数减1,『$baz』的值引用次数加1;
- 最后函数结束symbol『$var』被销毁,『$baz』的值引用次数减1;
看到没,函数内部改变的,只不过是内部创建的『$var』的指向,而『$var』在函数退出后就被销毁了,跟『$bar』断绝了关系;
三、引用返回
『&』号除了可以用在变量赋值表达式1当中,也可以用在函数结构当中,函数名前面加『&』号表明这个函数返回一个引用:
<?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. ?>
如上述例子所示,为了改变一个symbol的引用,变量赋值表达式1也需要加『&』。
注1:严格来说应该叫做改变变量引用表达式。
四、引用传递
当函数参数是一个引用值,那么调用这个函数的入参只能是以下3种形式:
- 变量,例如foo($a);
- new语句,例如foo(new bar());
- 从函数中返回引用,例如:
<?php function &bar() { $a = 5; return $a; } foo(bar()); ?>