PHP基础知识点【一】引用变量

概念:在php中 引用 意味着用不同的名字访问同一个变量内容,这并不像 C 的指针:例如你不能对他们做指针运算,他们并不是实际的内存地址, 定义方式:用&来定义。

一.理解引用

1.程序一

        COW机制:当不使用引用时,变量采取写时复制的机制(COW),即 copy on write
        memory_get_usage()函数返回分配给 PHP 的内存量字节数
        range()函数 创建一个包含指定范围的元素的数组。

    $a = range(0,1000);//定义一个变量a
    var_dump(memory_get_usage());//打印内存使用情况
    $b = $a;//定义一个变量b, 把a复制给b,这个时候内部 a与b指向同一个内容空间
    var_dump(memory_get_usage());//所以这个时候内存变化不多
    $a = range(0,1000);//当a或者b发生改变时候,才会重新开辟一个内存来存储变量。
    var_dump(memory_get_usage());//第三次内存明显改变

/*
输出结果
int 378872
int 378960
int 515472
*/

2.程序二

当变量使用引用的时候,就不会有cow机制。

    $a = range(0,1000);//定义一个变量a
    var_dump(memory_get_usage());// 
    $b = &$a;//定义一个变量b, 把a复制给b,这个时候内部 a与b指向同一个内容空间
    var_dump(memory_get_usage());// 
    $a = range(0,1000);//由于b对a用了引用,也就是说b和a一样都指向统一个内存地址
    var_dump(memory_get_usage());//所以这个内存始终没有发现较大变化 
/*
输出结果
int 378872
int 378960
int 378896
*/

3.程序三

通过zval变量容器进行验证,php的变量都在zval的容器里。
    xdebug_debug_zval()查看zval结构体,需要安装xdebug插件
    xdebug_debug_zval()打印 指向内存空间的变量数,和是否被引用。函数传入变量名,会打印出来两个值refcount, is_ref,refcount表示zval变量容器的个数, is_ref布尔值,真表示引用。
    unset()函数 ,unset一个引用的变量,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。

    $a = 99;
    xdebug_debug_zval('a');// //(refcount=1, is_ref=0),int 99
    $b = &$a;//使用 引用
    xdebug_debug_zval('a');//(refcount=2, is_ref=1),int 99
    $b = 99;
    xdebug_debug_zval('a');//(refcount=2, is_ref=1),int 99
    unset($b);//会取消引用,不销毁空间,也就是变量a还是有的,内容也不变
    xdebug_debug_zval('a');//(refcount=1, is_ref=0),int 99

4.程序四

对象本身就是引用传递 

class Person{ public $name='tacks';}
$p1 = new Person();
xdebug_debug_zval('p1');
$p2 = $p1;
xdebug_debug_zval('p1');
$p2->name = 'php';
xdebug_debug_zval('p1');

#上面的代码修改p2对象的name时,p1对象的name也会变化,也就是对象默认时引用传值,而不是变量的cow机制

#如果不是将$p2 = $p1;赋值改成克隆$p2 = clone $p1;,那么这两个对象就是两块内存空间了。

5.程序五

引用作为函数参数传递时,是可以被函数内部更改的

function foo(&$var){
    $var++;
}
$a = 5;
foo($a);
echo $a;//6

6.程序六

如果对一个未定义的变量进行引用赋值、引用参数传递或引用返回,则会自动创建该变量。

function t(&$val){
}

$b = array();
t($b['b']);
var_dump(array_key_exists('b', $b)); // bool(true)
$c = new StdClass;
t($c->d);
var_dump(property_exists($c, 'd')); // bool(true) 

 

二.经典例题

1.例题一

#下面的程序运行的时候,每一次循环结束后变量$data的值是?,为什么?
$data = ['a','b','c'];
foreach($data as $k=>$v){
    $v = &$data[$k];
    //var_dump($data);
}
步骤:
    进入foreach循环 将$data的第一个元素的键赋值给$k ,值赋给$v
    第一次循环:$v = &$data[$k];也就是$v = &$data[0] = a;
              $v与$data[0]的地址 是一样的,都指向a的内存空间       $data=['a','b','c']
    第二次循环:$k=1;$v=b; $data[0]=b;($v与$data[0]的地址 是一样的) 
              $v=&$data[1]=b;也就是$v和$data[1]都指向b的内存空间 $data=['b','b','c']
    第三次循环:$k=2;$v=c; $data[1]=c;($v与$data[1]的地址 是一样的) 
              $v=&$data[2]=c; 也就是$v和$data[1]都指向c的内存空间$data=['b','c','c']

2.例题二

#最后$arr的值是多少?
$arr = array('a','b','c');
foreach($arr as &$v){}
foreach($arr as $v){}
//var_dump($arr);
数组执行foreach循环时,是通过移动数组内部指针来实现的。
    在第一个foreach结束的时候 $v是引用变量与$arr[2]指向同一个地址空间
    所以之后$v的任何修改都会影响到$arr,
    在第二个foreach的循环开始,
        第一轮:$v=a 所以$arr[2]也是a  arr数组的内容就是['a','b','a']
        第二轮:$v=b 所以$arr[2]也是b  arr数组的内容就是['a','b','b']
        第三轮:$v=b 所以$arr[2]也是b  arr数组的内容就是['a','b','b']
打印出来的arr就是下面的结果,同时$arr[2]还是引用.
array (size=3)
  0 => string 'a' (length=1)
  1 => string 'b' (length=1)
  2 => &string 'b' (length=1)

3.例题三

#最终$arr的值?
$arr = [1,2,3];
foreach($arr as &$value){
    $value *= $value;
}

foreach($arr as $value){
    echo  $value;
}
//var_dump($arr);
通过在 $value 之前加上 & 来修改数组的元素。此方法将以引用赋值而不是拷贝一个值。
    所以第一个foreach过后$arr的值会被改变[1,4,9],同时$arr[2]是与$value引用
    第二个foreach中$arr[2]是与$value引用
    第一次循环 $value=1 $arr[2]=1 所以$arr=[1,4,1];
    第二次循环 $value=4 $arr[2]=4 所以$arr=[1,4,4];
    第三次循环 $value=4 $arr[2]=4 所以$arr=[1,4,4];

三.小结

基本的引用变量的题目,只要理解&的意思,按照步骤一步一步来,基本上都可以知道程序的答案

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值