查看: 224|回复: 0

[PHP代码] PHP 引用变量

发表于 7 天前
太阳http代理AD
1、引用变量的定义

在PHP 中引用的意思是:不同的名字访问同一个变量内容.使用&表示

使用 & 会使(如$a = &$b)指向同一个内存地址(这并不像 C 的指针:例如你不能对他们做指针运算,他们并不是实际的内存地址),一个发生改变,另一个也会发生改变

2、使用 memory_get_usage() 函数观察内存的变化 2.1、不使用 &

因为PHP 中COW(Copy On Write) 会导致赋值是引用上一个变量的地址(内存不会发生太大变化),只有在发生 写 操作的时候,才会开辟新的内存地址

  1. $a = range(0,1000);
  2. var_dump(memory_get_usage());
  3. $b = $a;
  4. var_dump(memory_get_usage());
  5. $a = range(0,1000);
  6. var_dump(memory_get_usage());
复制代码
  1. 运行结果:
复制代码

内存在第一次和第二次并没有太大的差异,第三次产生较大差异

2.2、使用 &
  1. $a = range(0,1000);
  2. var_dump(memory_get_usage());
  3. $b = &$a;
  4. var_dump(memory_get_usage());
  5. $a = range(0,1000);
  6. var_dump(memory_get_usage());
复制代码

运行结果:

内存在过程中基本没有发生变化,虽然第三步进行了写操作,但是 $a,$b引用的同一个地址,就不需要开辟新地址

3、使用xdebug 观察

xdebug 的安装方法 网上很多,这里不细讲(php 的一个扩展插件而已)

3.1、不使用 &
  1. //zval 变量容器
  2. $a = range(0, 3);
  3. xdebug_debug_zval('a');
  4. //定义变量b,把a的值赋值给b
  5. $b = $a;
  6. xdebug_debug_zval('a');
  7. //修改a
  8. $a = range(0, 3);
  9. xdebug_debug_zval('a');
复制代码

运行如下:

refcount用以标识指向这个zval变量容器的变量个数

is_ref(bool),标识此变量是否属于引用集合

第二步只进行了COPY 操作,使$a , $b 指向同一个内存地址, refcount = 2,而第三步 发生了写操作(is_ref=0 不是引用),重新开辟了内存地址,refcount= 1

3.2、使用 &
  1. //zval 变量容器
  2. $a = range(0, 3);
  3. xdebug_debug_zval('a');
  4. //定义变量b,把a的值赋值给b
  5. $b = &$a;
  6. xdebug_debug_zval('a');
  7. //修改a
  8. $a = range(0, 3);
  9. xdebug_debug_zval('a');
复制代码

运行结果:

采用了 引用(&),所以 从第二步开始 refcount = 2,is_ref = 1(引用) ,引用状态下不开辟新的内存地址;

4、特殊的引用(对象)

php 中 OBJECT 本身就是引用传值(自 PHP 5 起,new 自动返回引用,因此在此使用 =& 已经过时了并且会产生 E_STRICT 级别的消息。)

  1. //对象本身就是引用传递
  2. class Person
  3. {
  4. public $name = 'zs';
  5. }
  6. $p1 = new Person;
  7. xdebug_debug_zval('p1');
  8. $p2 = $p1;
  9. xdebug_debug_zval('p1');
  10. $p2->name = 'ls';
  11. xdebug_debug_zval('p1');
复制代码

运行结果:

OBJECT 赋值情况下 会共享内存地址,但本身又不是引用。

5、unset
  1. //unset 只会取消引用,不会销毁空间
  2. $a = '';
  3. xdebug_debug_zval('a');
  4. $b = &$a;
  5. xdebug_debug_zval('a');
  6. unset($b);
  7. xdebug_debug_zval('a');
复制代码

运行结果:

所以在第一步的时候 refcount = 0

对应 引用(&),unset只会取消引用,而不会销毁内存地址

5、总结

通过对 is_ref 判断是否是引用变量,如果是引用变量,修改时直接修改(原内存地址),否则,则需要进行 分离(重新开辟新地址),而 usset 变量只是取消该变量的引用,而不会消除内存地址,只有当refcount = 0;内存才有可能被回收



太阳http代理AD
回复

使用道具 举报