1、请写出下列的结果:
$a = 123; $b = &$a; var_dump($b);//123 $a = 456; var_dump($b);//456 unset($a); var_dump($b);//456
关于变量引用:
(1)普通的变量赋值。
执行COW机制,即copy On Write。
当一个变量等于另一个变量时,并没有增加一块新空间的开销,而是两个变量指向同一个内存空间;
当其中一个变量重写时(无论值是否改变),会为这个重写的变量增加一块单独的内存空间。
示例:
$a = range(0,1000); var_dump(memory_get_usage());//打印内存,878408 $b = $a; var_dump(memory_get_usage());//打印内存,878408,发现没变化或变化很小 $a = range(0,1000);//$a重新赋值,虽然值没有变化 var_dump(memory_get_usage());//打印内存,915328,发现变化很大,因为$a重新使用了一块空间。
(2)当进行引用赋值。
变量永远指向同一个内存空间,所以内存不会变化或变化很小。
$a = range(0,1000); var_dump(memory_get_usage());//打印内存,878408 $b = &$a; var_dump(memory_get_usage());//打印内存,878432,发现变化很小 $a = range(0,1000);//$a重新赋值,虽然值没有变化 var_dump(memory_get_usage());//打印内存,878432,发现没变化或变化很小。
扩展:可以打印zval结构体来查看变量的底层的存储,zval就是变量容器,管理变量内容。安装xdebug扩展。
$a = range(1,3);
$b = &$a; xdebug_debug_zval('a');
recount=1;说明只有一个变量指向这个内存空间。
is_ref=1;说明有一个引用
2、关于对象的赋值:
class user{ public $name = ''; public function setName($newName = ''){ $this->name = $newName; } public function getName(){ return $this->name; } } $a = new user(); $b = $a; $c = clone $a; $a->setName('123'); var_dump($b->getName());//string '123' var_dump($c->getName());//string ''
正确结果是:123;说明对象之间的赋值,本身就是引用传值,指向同一个内存空间,如果不想使用同一个对象,就需要使用clone关键字复制一个对象。
3、请分析下面程序,写出结果:
$data = array('a','b','c'); foreach ($data as $k => $v) { $v = &$data[$k]; }
问: (1)程序运行时,每一次循环结束后变量$data的值是什么,请解释。 (2)程序执行完成后,变量$data的值是什么?请解释。 分析: 第一轮循环: $k=0; $v='a'; $v = &$data[0];//$v和$data[0]指向同一个空间 所以第一轮结果: $data = array('a','b','c'); 第二轮循环: $k=1; $v='b';//因为第一轮$v和$data[0]指向同一个空间,所以$v变化,$data[0]就变化。 $v = &$data[1];//$v和$data[1]又指向同一个空间 所以第二轮结果: $data = array('b','b','c'); 第三轮循环: $k=2; $v='c';//因为第二轮$v和$data[1]指向同一个空间,所以$v变化,$data[1]就变化。 $v = &$data[2];//$v和$data[2]又指向同一个空间 所以第二轮结果: $data = array('b','c','c'); 最终结果: var_dump($data);//array('b','c','c');