php

php 变量和函数名前加&符号

2023-10-11

在php中我们常看到在在php变量前面加个&符号,这个就是php中引用符号了,它可以用于各种变量、函数、对象。下面介绍php&符号用法,在 PHP 中引用意味着用不同的名字访问同一个变量内容,这并不像 C 的指针,它们是符号表别名。

注意在 PHP 中,变量名和变量内容是不一样的,因此同样的内容可以有不同的名字,PHP的引用是通过在变量名或者函数名前加&符号来实现的,下面解释一下引用的几种用法:


先来看官方法的说明:

引用做什么

PHP 的引用允许用两个变量来指向同一个内容,意思是当这样做时:

<?php

$a = &$b;

?>

这意味着 $a 和 $b 指向了同一个变量.


Note:

$a 和 $b 在这里是完全相同的,这并不是 $a 指向了 $b 或者相反,而是 $a 和 $b 指向了同一个地方。


Note:

如果具有引用的数组被拷贝,其值不会解除引用,对于数组传值给函数也是如此。


Note:

如果对一个未定义的变量进行引用赋值、引用参数传递或引用返回,则会自动创建该变量,

Example #1 对未定义的变量使用引用:

<?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)

?>


同样的语法可以用在函数中,它返回引用,以及用在 new 运算符中(PHP 4.0.4 以及以后版本)

<?php

$bar = &new fooclass();

$foo = &find_var($bar);

?>


自 PHP 5 起,new 自动返回引用,因此在此使用 =& 已经过时了并且会产生 E_STRICT 级别的消息.


Note:

不用 & 运算符导致对象生成了一个拷贝.如果在类中用 $this,它将作用于该类当前的实例.没有用 & 的赋值将拷贝这个实例(例如对象)并且 $this 将作用于这个拷贝上,这并不总是想要的结果.由于性能和内存消耗的问题,通常只想工作在一个实例上面.尽管可以用 @ 运算符来抑制构造函数中的任何错误信息,例如用 @new,但用 &new 语句时这不起效果.这是 Zend 引擎的一个限制并且会导致一个解析错误.


首先是变量的简单引用,允许你用两个变量来指向同一个内容,举个简单的例子:<?php


$a = 5;


$b = &$a;


echo $b;


$a++;


echo $b;


?>


运行这段代码是让$b来引用$a的内容,然后改变$a的内容,$b的内容也会随之变化.同样的语法可以用在函数中,它返回引用,以及用在new 运算符中:<?php


$bar = &new fooclass();


$foo = &find_var ($bar);


?>


引用做的第二件事是用引用传递变量.这是通过在函数内建立一个本地变量,并且该变量在呼叫范围内引用了同一个内容来实现的.


说的通俗点就是一个函数的参数是一个本地变量的引用.下面再举例说明一下:<?php


function foo(&$val1, $val2) {


$val1 += 1;


$val2 += 1;


}


$a=5;


$b=10;


foo($a,$b);


echo $a;


echo $b;


?>


运行这段代码是给函数传递两个参数,一个是引用$a的内容,一个是$b的值,在执行此函数后,发现$a的内容改变了,而$b的内容则没有变化.PHP引用的第三个用法是引用返回,这个用法理解起来有点难度,引用返回用在当你想用函数找到引用应该被绑定在哪一个变量上面时.当返回引用时,使用此语法:说的简单点,就还是引用函数的返回.但和参数传递不同,必须在函数定义和函数引用这两个地方都用 & 符号.下面举个例子:<?php


function &find_var ($param)


{


/* ...code... */


return $found_var;


}


$foo =& find_var ($bar);


$foo->x = 2;


?>


这个例子给$foo 赋值是函数find_var的返回引用,所以在给$foo->x赋值时就是给find_var的返回引用赋值,而不是简单的赋值.PHP引用的最后一个用法是引用定位,主要有两个应用:一个是global 引用,当用 global $var 声明一个变量时实际上建立了一个到全局变量的引用.也就是和$var =& $GLOBALS["var"];是一样的.另外一个是$this的用法,在一个对象的方法中,$this 永远是调用它的对象的引用.与指针的区别引用与指针很像,但是其并不是指针.


看如下的代码:<?php


$a = 0;


$b = &a;


echo $a; //0


unset($b);


echo $a; //0


?>


由于$b只是$a的别名,所以即使$b被释放了,$a没有任何影响,但是指针可不是这样的.


看如下代码:<?php


#include


int main(int argc, char const *argv[]) {


int a = 0;


int* b = &a;


printf("%in", a); //0


free(b);


printf("%in", a); //*** error for object 0x7fff6350da08:


pointer being freed was not allocated


}


?>


由于b是指向a的指针,所以释放了b的内存之后,再访问a就会出现错误,比较明显的说明了PHP引用与C指针的区别.


对象与引用


在PHP中使用对象的时候,大家总是被告知"对象是按照引用传递的",其实这是个误区.PHP的对象变量存储的是此对象的一个标示符,在传递对象的时候,其实传递的就是这个标示符,而并不是引用.


看如下代码:<?php


$a = new A;


$b = $a;


$b->testA = 2;


/*


* 此时$a,$b的关系:


*        +-----------+      +-----------------+


* $a --> | object id | ---> | object(Class A) |


*        +-----------+      +-----------------+


*                               ^


*        +-----------+          |


* $b --> | object id | ---------+


*        +-----------+


*


*


*/


$c = new B;


$a = $c;


$a->testB = "Changed Class B";


/*


* 此时$a,$b,$c的关系:


*        +-----------+      +-----------------+


* $b --> | object id | ---> | object(Class A) |


*        +-----------+      +-----------------+


*


*        +------------+


* $a --> | object id2 | -------------+


*        +------------+              |


*                                    v


*        +------------+      +-----------------+


* $c --> | object id2 | ---> | object(Class B) |


*        +------------+      +-----------------+


*/


echo "object a: "; var_dump($a); //["testB"]=> string(15)


"Changed Class B"


echo "object b: "; var_dump($b); //["testA"] => int(2)


echo "object c: "; var_dump($c); //["testB"]=> string(15)


"Changed Class B"


如果对象是按照引用传递的,那么$a,$b, $c输出的内容应该一样,事实上结果并非如此.看下面通过引用传递对象的列子:$aa = new A;


$bb = &$aa;  // 引用


$bb->testA = 2;


/*


* 此时$aa, $bb的关系:


*


*         +-----------+      +-----------------+


* $bb --> | object id | ---> | object(Class A) |


*         +-----------+      +-----------------+


*              ^


*              |


* $aa ---------+


*


*


*/


$cc = new B;


$aa = $cc;


$aa->testB = "Changed Class B";


/*


* 此时$aa, $bb, $cc的关系:


*


*         +-----------+      +-----------------+


*         | object id | ---> | object(Class A) |


*         +-----------+      +-----------------+


*


* $bb ---->-----+


*               |


* $aa ---->-----+


*               |


*               v


*         +------------+


*         | object id2 | --------------+


*         +------------+               |


*                                      v


*         +------------+      +-----------------+


* $cc --> | object id2 | ---> | object(Class B) |


*         +------------+      +-----------------+


*/


echo "object aa: "; var_dump($aa); //["testB"]=>string(15)


"Changed Class B"


echo "object bb: "; var_dump($bb); //["testB"]=>string(15)


"Changed Class B"


echo "object cc: "; var_dump($cc); //["testB"]=>string(15)


"Changed Class B"


此时$aa,$bb,$cc三者内容完全一样,所以可以看出对象并不是按照引用传递,要尽快走出这个误区.