最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • PHP引用的秘密(三) 数组引用中的火坑

    正文概述 转载于:掘金(传达室老大爷)   2021-06-16   317

    书接上回

    在数组中, 我们同样可以进行引用传值, 引用返回值, 以及取消引用的操作. 只不过是在引用的核心逻辑外面套了一层数组的外衣.

    但针对数组的模式, 有2点需要注意的火坑:

    先看下面两个例子:

    这是引用在数组中的一般应用,和普通赋值没有什么区别:
    $arr = array(1, 'test');
    $p =& $arr[1];  // $p和$arr[1]都指向了test
    $new = 'new';
    $arr[1] =& $new;//$new给$arr[1]赋予新的引用,都指向了new
    echo $arr[1]; // echo 'new';
    echo $p.'<br>'; //'test',$p的指向并没变;
    
    这个是数组引用特殊的地方,不注意的话会出问题:
    $array1 = array(1,2);
    $x = &$array1[1];  //x和$array1[1]指向同一个变量
    $array2 = $array1;  // 这里是数组对数组整体的赋值,将其中元素的引用关系,也进行了传递!
    $array2[1]=22;      // (changing [0] will not affect $array1)
    var_dump($array2,$x);  //同时修改了$array1[1]
    

    上面第二个例子中, $array2 = $array1, 这一步非常重要, 我们如果不注意, 可能就认为这是一个普通赋值, 不存在引用关系. 但实际上, 元素级的引用关系却进行了传递, 在新数组下得到了保留.

    这就牵出了数组型引用的第一个坑:

    元素级用 & 数组引用

    上面那个例子是元素级别的引用关系, 它可以通过普通数组间赋值来传递引用关系.

    我们再来看数组级别的引用:

    $brr1=[1,2,3,4];
    $brr2=[5,6,7,8];
    $brr3=&$brr1;  //建立brr3和brr1的引用关系;
    $brr2=$brr3; //对brr2进行整体赋值
    $brr3[3]=100;
    print_r($brr2); //依然是[1,2,3,4]
    print_r($brr1); //[1,2,3,100], 被修改;
    

    可以看到,数组级别的引用关系, 无法通过普通赋值来传递. 引用关系不会保留. 只能通过引用赋值来传递.

    这就好比, 你(数组$a) 和 你的老婆(数组$b,引用赋值), 或和情人(普通赋值), 她们怀了你的孩子(数组元素), 这个孩子都是你的家人(引用关系), 而且你和你的老婆也是一家人(引用关系), 但和你的情人却不是一家人.

    元素级别的引用和数组整体的引用, 是相互独立. 当我们为数组进行整体赋值的时候, 元素级别的应用会进行传递和保留, 而数组级别的引用却不会, 需要单独加&说明.

    所以在进行元素级引用的时候要格外小心!!!尽量少用, 可以通过条件判断, 如果发生改变就重新赋值的操作, 更安全一些.

    好的,我们再来看一下第二个坑:

    foreach()引用的小尾巴

    这个函数可以用来遍历数组, 并可与引用组合使用, 实现数组赋值, 修改等操作. 举例:

    $a1=[1,2,3,4]
    foreach ($a as &$value) {
    $value = $value * 2;
    }
    print_r($a1);  //[2,4,6,8] 通过引用实现了对数组所有元素的修改
    

    现在问题来了, 数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。这个就是 foreach引用的小尾巴.

    此时数组$a1的结构已经变为了:

    $a1=[$a1[0]=>2, $a1[1]=>4, $a1[2]=>6, &$a1[3]=>8]

    注意最后一项a1[3],它有一个引用关系.a1[3], 它有一个引用关系. 是a1[3],它有一个引用关系.是a1[3]与函数参数$var之间的引用关系. 可以理解为:

    $a1[3]=&$value=8;

    如果我们忽视这个小尾巴的话, 就会被它反噬, 比如我们现在再遍历一次数组的话, 你就会发现:

    $a1=[1,2,3,4]
    foreach ($a as &$value) {
    $value = $value * 2;
    }
    print_r($a1);
    foreach ($a as $key => $value){
    echo "$key to $value";
    }  //0 => 2  1 => 4  2 => 6  3 => 6  
    

    此时, $a1[3]=6. Why?

    因为第二次foreach的时候, a轮流赋值给a轮流赋值给a轮流赋值给value, 而同时也修改着$a[3].

    我把每一步分解一下:

    $value= $a1[0]=2, 此时$a1[3] = 2;
    $value= $a1[1]=4, 此时$a1[3] = 4;
    $value= $a1[2]=6, 此时$a1[3] = 6;
    $value= $a1[3]=6, 此时$a1[3] = 6;
    

    看到这里, 大家应该都明白了, foreach (&)会在遍历结束后,保留最后一项的引用关系, 最终导致被引用数组的最后一项发生改变.

    那么如何规避这个问题? 2个办法:

    1. unset, 每次foreach遍历后,都对引用变量$value进行unset, 解除它与数组元素的引用关系.

    2. 手动赋值

       \$a=[1,2,3,4];
       foreach ($a as $key => $value){
       $a[$key]=$value*2;
       }
       print_r($a); //可以通过这样的方式进行赋值,避开引用;
      

    以上就是关于php数组中涉及引用的两个坑, 这两个坑都很隐蔽, 各位在写代码时要特别小心!

    学习不易,请勿私自转载, 否则别怪老大爷不客气.

    参考资料: www.php.net 官方文档


    起源地下载网 » PHP引用的秘密(三) 数组引用中的火坑

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元