解释
这里基于php7.2.5进行测试,php7之后内部构造变革该当不是太大,但与php5.X有差别。
什么是引用
在PHP中引用是一种数据类型(构造),是指 指向同一个类型的数据构造,来看详细存储构造
struct _zend_reference { // 引用计数用于垃圾回收 先忽略zend_refcounted_h gc; // zval是另一个变量 zval还记得吗 存储变量的构造 // 这里val指向另一个zvalzval val;};
忘了的这里看zval
如何利用
// 定义变量$a = "hello";// &天生引用变量$b = &$a;echo $b;echo PHP_EOL;
php hello.phphello
结果大家都知道,$b与$a的值是相同的,而且你还知道,修正$b同时也会浸染与$a.
$a = "hello";$b = &$a;echo "b:".$b;echo PHP_EOL;$b = "world";echo "a:".$a;echo PHP_EOL;
php hello.phpb:helloa:world
如何实现
回顾zval的格式实行第一句时,天生的数据构造是这样的(简版示意图,真实构造繁芜)
当实行$b = &$a时,&$a会师长西席成引用类型的数据构造,然后引用的zval指向之前的hello的构造,$a,$b则共同指向引用构造。
那么在修正$b时,实际是修正了引用类型指向的zend_value,以是导致$a的值也发生了变革。
小结
php中利用&天生一个引用类型的数据,这个引用的zval指向原变量所指向的zval, 变量则会指向这个运用构造,当发生引用赋值之后,被赋值的变量也会指向这个引用,变动个中任何一个变量,所有的变量都会发生变革。类似于你大名叫大壮, 小名叫小壮, 但是身份证都是xxoo100, 无论修正大壮还是小壮的身份证,他始终只有一个身份证。
扩展
我们可能听过取地址符这么一种说法,那么在C措辞或者GO中,通过利用&可以获取到变量的内存地址。
#include <stdio.h>#include<string.h>int main(){char str[] = "hello"; // &获取变量的内存地址printf("%p\n", &str);}
gcc pointer.c -o pointer./pointer0x7ffee6d3292a
但是PHP的&并不是获取变量的地址,这是须要把稳的。
unset引用变量
unset($b);echo "a:".$a;echo PHP_EOL;echo "b:".$b;echo PHP_EOL;
php hello.phpa:worldPHP Notice: Undefined variable: b
unset($b)之后,只是销毁了变量b及b对引用的指向,没有影响$a。
foreach中的引用
$list = [ ['id' => 3, 'total' => 3], ['id' => 4, 'total' => 4], ['id' => 5, 'total' => 5],];foreach ($list as $key => &$info) { $info['total'] = $info['total'] + 3;}print_r($list);// 一顿操作$info['name'] = "hello";print_r($info);
php hello.phpArray( [0] => Array ( [id] => 3 [total] => 6 ) [1] => Array ( [id] => 4 [total] => 7 ) [2] => Array ( [id] => 5 [total] => 8 ))Array( [id] => 5 [total] => 8 [name] => hello)
这里在foreach之后须要把info unset掉防止发生数据问题。
总结
PHP中通过&获取对变量的引用,本色是多个变量通过中间引用类型(不是指向内存地址),指向同一个值。