[TOC]
* * * * *
### 一. 概念
* 即用不同的名字访问同一个变量内容;
### 二. 定义符号
* 使用 & 符号;
### 三. COW机制
写时复制(Copy-on-Write,也缩写为COW),顾名思义,就是在写入时才真正复制一份内存进行修改;
~~~
$a = range(0,1000);
var_dump(memory_get_usage()); // 打印内存使用情况
$b = $a;
var_dump(memory_get_usage());
// 此时 , $a 与 $b 指向同一个内存空间, 并不会因为$b的创建而开辟另一块内存空间
$a = range(0,1000);
var_dump(memory_get_usage());
// 此时, $b还是指向最初的空间, 而$a会指向新的内存空间;
~~~
### 四. PHP引用变量的原理
~~~
$a = range(0,1000);
var_dump(memory_get_usage());
$b = &$a;
var_dump(memory_get_usage());
// 此时 , $a 与 $b 在一般情况下永远指向同一个内存空间, 并不会因为谁的更改而开辟另一块内存空间
$a = range(0,1000);
var_dump(memory_get_usage());
// 此时, $a 与 $b 还是指向最初的空间; 改变的只是内存空间的值;
~~~
### 五. xdebug_debug_zval()函数 的使用
* 每个php变量存在一个叫"zval"的变量容器中。
* 一个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息。
* 一个是"is_ref",是个bool值,用来标识这个变量是否是属于引用集合(reference set)。
* 通过这个字节,php引擎才能把普通变量和引用变量区分开来。
* 由于php允许用户通过使用&来使用自定义引用,zval变量容器中还有一个内部引用计数机制,来优化内存使用。
* 另一个额外字节是"refcount",用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。
~~~
$a = 123;
xdebug_debug_zval('a'); // a:(refcount=0, is_ref=0)int 123
$b = $a;
xdebug_debug_zval('a'); // a:(refcount=0, is_ref=0)int 123
$c = &$a;
xdebug_debug_zval('a'); // a:(refcount=2, is_ref=1)int 123
~~~
~~~
$a = range(0,3);
xdebug_debug_zval('a');
$b = $a;
xdebug_debug_zval('a');
$c = &$a;
xdebug_debug_zval('a');
打印结果 :
a:
(refcount=1, is_ref=0)
array (size=4)
0 => (refcount=0, is_ref=0)int 0
1 => (refcount=0, is_ref=0)int 1
2 => (refcount=0, is_ref=0)int 2
3 => (refcount=0, is_ref=0)int 3
a:
(refcount=2, is_ref=0)
array (size=4)
0 => (refcount=0, is_ref=0)int 0
1 => (refcount=0, is_ref=0)int 1
2 => (refcount=0, is_ref=0)int 2
3 => (refcount=0, is_ref=0)int 3
a:
(refcount=2, is_ref=1)
array (size=4)
0 => (refcount=0, is_ref=0)int 0
1 => (refcount=0, is_ref=0)int 1
2 => (refcount=0, is_ref=0)int 2
3 => (refcount=0, is_ref=0)int 3
~~~
### 六. 对象本身就是引用传值
~~~
class Person
{
public $name = "zhangsan";
}
$p1 = new Person;
xdebug_debug_zval('p1');
$p2 = $p1;
xdebug_debug_zval('p1');
$p2->name = "zhouliuwan";
xdebug_debug_zval('p1');
打印结果 :
p1:(refcount=1, is_ref=0)
object(Person)[1]
public 'name' => (refcount=1, is_ref=0)string 'zhangsan' (length=8)
p1:(refcount=2, is_ref=0)
object(Person)[1]
public 'name' => (refcount=1, is_ref=0)string 'zhangsan' (length=8)
p1:(refcount=2, is_ref=0)
object(Person)[1]
public 'name' => (refcount=0, is_ref=0)string 'zhouliuwan' (length=10) // name值已经发生改变
~~~