引用是什么?
与C语言中的指针不同,C语言中是内存中的地址,而PHP中是符号表中的变量(也叫符号)的名字,意味着可以使用不同的名字访问同一个zval变量容器,类似于unix系统的硬链接的概念。例如,下面的两个变量是指向zval变量容器,一个变量改变另一个也会改变。
$a = 'first'; $b = & $a; echo $a ; // first echo $b ; // first $b = 'secondary'; echo "------------"; echo $a ; // secondary echo $b ; // secondary
写时复制
对于使用一个变量的值给另一个变量赋值,传统意义上是变量值内存的复制,意味需要申请与原来变量一样大小的内存空间,这种做法非常浪费内存空间。PHP内核对于变量的赋值采取一种非常巧妙的机制——写时复制。那么什么是写时复制呢,请看下面例子。
$var = "first"; xdebug_debug_zval('var'); $var1 = $var; xdebug_debug_zval('var'); $var2 = $var; xdebug_debug_zval('var1'); $var2 = 'secondary'; xdebug_debug_zval('var2'); xdebug_debug_zval('var'); $var3 = $var; xdebug_debug_zval('var'); xdebug_debug_zval('var1'); xdebug_debug_zval('var2'); xdebug_debug_zval('var3'); 输出: var: (refcount=1, is_ref=0)='first' var: (refcount=2, is_ref=0)='first' var1: (refcount=3, is_ref=0)='first' var2: (refcount=1, is_ref=0)='secondary' var: (refcount=2, is_ref=0)='first' var: (refcount=3, is_ref=0)='first' var1: (refcount=3, is_ref=0)='first' var2: (refcount=1, is_ref=0)='secondary' var3: (refcount=3, is_ref=0)='first'
代码分析:
1、一开始$var的refcount为1,在赋值给$var1后refcount成为了2,说明$var1和$var是指向的同一个zval变量容器。
2、$var在赋值给$var2后, 发现$var1的refcount成为了3,其实这时候$var、$var1和$var2的refcount的值都是3,更加说明用一个变量给另一个变量赋值,其实就是引用,都指向同一个zval变量容器。
3、紧接着将$var2赋值为secondary,发现,$var2的refcount为1,$var的refcount为2。这是为什么呢?这时候就体现出了写时复制的作用,由于$var2被赋予了新的值,PHP内核需要申请新的内存空间来存储,而此时$var2不再表示是$var指向的变量,所以$var的refcount减1。
4、再将$var赋给$var3, 此时$var、$var1和$var3的refcount都为3,$var2的refcount仍然为1。
总结一下:
写时复制的机制,就是多个指向同一内存空间的变量,当其中一个变量被赋予其他值的情况下,PHP内核才会去申请新的内存空间存储新值。
其实,写时复制也是一种特殊的引用,只不过这个原有引用关系会在有变量被赋予新值的情况下被破坏掉。
每个php变量存在一个叫"zval"的变量容器中