----- 最后更新【2018-12-6】-----
目录预览:
》一、概念
》二、变量的存储方式
》三、变量的引用机制
》四、从zval变量容器底层去了解引用
》五、unset与引用
》六、对象与引用
》七、测试题
》八、参考文献
一、概念
在PHP中引用意味着用不同的名字访问同一个变量内容。
定义方式:使用&
符号
二、变量的存储方式
在讲解变量的引用之前,我们先来了解一下变量的存储方式。
下面以一个例子来说明:
// 1、定义一个变量$a$a = '111'; //当我们定义一个变量$a时,那么程序就会为它在内存当中开启一个内存空间,此时$a就指向这个内存空间(内存空间里存储着相应的值)。// 2、定义一个变量$b,然后将$a的值赋值给$b$b = $a; //这时程序不会为变量$b再开启一个内存空间,这里涉及到了php的COW机制。//只有对$a或$b中的其中一个进行修改时,才会进行复制一份内存。//3、修改$a$a = '222'; //复制一份内存,用于存储修改后的值。
附:COW(copy on write)是内存优化的常见手段,在php中也采用了这种方式来优化内存。COW:写时复制,即只有当对其中一个或多个变量进行写操作的时候,才会复制一份内存,对其内容进行修改。
验证:
php有个函数memory_get_usage()可以用来查看PHP所使用的内存情况。
验证内存变化
如上图可以看出,前面两个打印出来的内存使用情况相差并不大,而第三个则拉开了很大的差距,这是因为当修改变量$a时,程序为变量$a复制了一份内存用于存储修改后的值。
三、变量的引用机制
我们接着上面的例子,把$b = $a
改为$b = &$a
,结果分析如下:
从上面可以看出,三个打印出来的内存使用情况差别都不大,这就是引用的机制。上面的情况无论你是修改$a还是$b,最后$a和$b都会变为修改后的值,程序并没有为修改后的变量开启新的内存空间。
四、从zval变量容器底层去了解引用
众所周知php的变量都是通过zend引擎来处理的,而zval结构体则是管理我们变量的一个容器,而xdebug_debug_zval函数则是我们调试zval结构体的一个好工具(注意,想使用该函数需要安装Xdebug插件)。
使用函数xdebug_debug_zval()打印出来的zval结构如下:
<?php$a = 'aaa'; xdebug_debug_zval('a');
在浏览器输出如下内容:
a: (refcount=1, is_ref=0)string 'aaa' (length=3)
结构说明:
1)refcount表示引用计数,用来记录有多少个变量指向这个zval容器;
2)is_ref表示是否为引用,一个bool型的值;
3)表示数据的类型;
4)最后则为它的值。
注意:当refcount为1的时候,is_ref必须为0。当refcount为0的时候,该容器会被删除掉,释放空间出来。
没有引用
使用引用
五、unset与引用
当一个变量是使用了引用时,unset函数只会删除引用,并不会销毁内存空间。
由如下分析可以证明:
从上面可以看出,三次打印出来的内存使用情况基本没有什么变动。
六、对象与引用
在PHP中,对象本身就是引用传递。
验证如下:
分析:
1)当定义$a2 = $a1时,zval结构体的refcount值由1变为2;
2)此时无论修改的是$a2->type还是$a1->type的值,其实修改的都是同时一个空间里的值;
3)由此可以发现此时并没有使用到COW机制;
4)这是因为这种情况下$a1和$a2引用到了同一个对象。
七、测试题
1、写出如下程序的输出结果
$data = ['a', 'b', 'c'];foreach($data as $k => $v){ $v = &$data[$k]; }//程序运行时,每一次循环结束后变量$data的值是什么?//程序执行完后,变量$data的值是什么?
运行结果如下:
作者:Nosee123
链接:https://www.jianshu.com/p/f643bd68caa7