一. PHP引用变量考察点
1. PHP的引用变量的概念及定义方式
概念
在PHP中,引用意味着用不同的名字访问同一个变量内容。
定义方式
使用 & 符号
2. 延伸:PHP引用变量的原理
1)赋值
将一个变量的值赋值给另一个变量,其中一个变量的值进行改变,会重新进行拷贝,此时会再开辟一个新的内存空间。
// 1. 定义一个变量
$a = range(0, 1000); // 在内存中开辟一片空间,存储变量a
var_dump(memory_get_usage()); // int(406512)
// 2. 定义变量 b,将 a变量的值赋值给 b
$b = $a; // 将变量b 指向 变量a开辟的空间中
var_dump(memory_get_usage()); // int(406568)
// 3. 对 a进行修改
$a = range(0, 1000);
var_dump(memory_get_usage()); // int(406568)
原理:使用了 COW(Copy On Write)机制 : 对 $a或 $b 其中一个进行改变,内存空间才会发生改变。
- 在内存中开辟一片空间存储变量a;
- 将变量b 指向 变量a的内存空间中;
- 对变量a进行修改(对a进行写操作),此时会再开辟一片内存空间存储a和a和a和b(原来的a和a和a和b被改变)
2)引用
两个变量无论何时都共用一个内存空间(对其中一个的值进行更改的时候,不会开辟新的内存空间)
// 1. 定义一个变量
$a = range(0, 1000);
var_dump(memory_get_usage());
// 2. 定义变量b, 将a变量的值赋值给b
$b = &$a;
var_dump(memory_get_usage());
// 3. 对a进行修改
$a = range(0, 1000);
var_dump(memory_get_usage());
原理:
- 定义一个变量
$a(开辟一个内存空间存储变量$a); - 定义变量
$b,将$b,将$b,将$a的地址给了$b,此时$b,此时$b,此时$b与$a指向同一个内存空间,且永远指向该内存空间(不会再重新拷贝,改掉的只是该内存空间的值); - 对a进行修改(不会再开辟内存空间),此时a和a和a和b的值,都是修改后的值;
3)unset 只会取消引用,不会销毁内存空间
$a = 1; // 开辟一个内存空间存储变量a,并赋值为1
$b = &$a; // 将$a的引用赋值给$b,此时$a和$b指向同一个内存空间(永久指向)
unset($b); // 此时取消的是$a和$b的引用,不会取消内存空间
echo $a; // 1
4) 对象本身就是引用传递,因此,在修改的时候,不会再重新开辟内存空间
class Person
{
public $name = 'zhangsan';
}
$p1 = new Person; // 开辟一个内存空间存储$p1
$p2 = $p1; // 将$p1和$p2存入同一个内存空间(内存空间会变大)
$p2->name = 'lisi'; // $p1,$p2都为lisi,因为指向的是同一个内存空间
二. 真题
写出如下程序的输出结果:
$data = ['a', 'b', 'c'];
foreach ($data as $key => $val) {
$val = &$data[$key];
}
程序运行时,每一次循环结束后变量 $data 的值时什么?请解释
程序执行完成后,变量 $data 的值时什么?请解释
1)答案:
// 第一次循环
$data = ['a', 'b', 'c'];
// 第二次循环
$data = ['b', 'b', 'c'];
// 第三次循环
$data = ['b', 'c', 'c'];
// 程序执行完成后,变量 $data的值
$data = ['b', 'b', 'c'];
2)解析:
1)foreach ($data as $key => $val)
会将$data第一个元素的键名赋值给$key,将$data的第一个元素的值赋值给$val(即$k=0; $v=a;)
2) $val = &$data[$key];
$v = &$data[0];(即$v拿了$data[0]的地址)
$v = &$data[0] = a(此时$data[0]和$v都指向 a内存空间)
以上步骤即为:
1)第一次循环:
$k = 0;
$v = a;
$v = &$data[0];
($v = &$data[0] = a,$v 和 $data[0] 都指向 a内存空间) // 结果:$data = ['a','b','c'];
2)第二次循环:
$k = 1;
$v = b;
$data[0] = b;
$v = &$data[1];
($v = &$data[1] = b, $v 和 $data[1] 都指向 b内存空间) // 结果:$data = ['b','b','c'];
3)第三次循环:
$k = 2;
$v = c;
$data[1] = $c;
$v = &$data[2];
($v = &$data[2] = c, $v 和 $data[1] 都指向 c内存空间) // 结果:$data = ['b','c','c'];
3)代码测试:
$data = ['a', 'b', 'c'];
foreach ($data as $k => $v) {
$v = &$data[$k];
var_dump($data);
}
var_dump($data);
运行结果:
// 第一次循环后, $data 的值
array(3) {
[0] =>
string(1) "a"
[1] =>
string(1) "b"
[2] =>
string(1) "c"
}
// 第二次循环后, $data 的值
array(3) {
[0] =>
string(1) "b"
[1] =>
string(1) "b"
[2] =>
string(1) "c"
}
// 第三次循环后, $data 的值
array(3) {
[0] =>
string(1) "b"
[1] =>
string(1) "c"
[2] =>
string(1) "c"
}
// 程序执行完后, $data 的值
array(3) {
[0] =>
string(1) "b"
[1] =>
string(1) "c"
[2] =>
string(1) "c"
}