zoukankan      html  css  js  c++  java
  • 一次php foreach 变量作用域的踩坑记录

    记录一次因为对PHP作用域理解不够导致的小坑。

    自测需求的时候发现有一块地方数据很奇怪,要么该写的没有写入、要么数据被写入双份。剥离业务后的代码大概如下:

    <?php
    
    $arr = [
        ['is_checked'=>false,'k'=>1],
        ['is_checked'=>false,'k'=>2],
    ];
    
    foreach ($arr as  &$item) {
        if ($item['k']==1) {
            $item['is_checked'] = true;
        }
    }
    
    echo '<pre>';
    foreach ($arr as $item) {
        if ($item['is_checked']) {
            print_r($item);
        }
    }
    

    我预想中 上面的代码应该是只打印arr里的第一条记录,也就是['is_checked'=>true,'k'=>1],然而实际运行发现打印的是这样的:

    Array
    (
        [is_checked] => 1
        [k] => 1
    )
    Array
    (
        [is_checked] => 1
        [k] => 1
    )
    

    居然打印了两条记录,而且两条的k都是1。

    断点调试的时候也发现,运行到第二个foreach里的时候 arr确实变成了这样的数组:

    [
        ['is_checked'=>true,'k'=>1],
        ['is_checked'=>true,'k'=>1],
    ]
    

    仔细看代码,前面foreach的时候,循环里的变量是用的item,而且是取引用,后面的foreach也是item。我之前是认为这俩item的作用域是不重合的,也就是认为第一个foreach的作用域只在foreach代码块里(这点可能是受了golang变量作用域的影响)

    然而从结果来看,两个item应该是一样的,也就是第二个循环里的item还是前一个循环里的item,而前一个循环里的item是对数组里元素取的引用,也就是说,第一个循环结束后,item还是指向$arr的第二个元素。第二个foreach开始的时候,$arr的第一个元素的值被赋给item,这样$arr的第二个元素就被第一个元素覆盖了,所以产生了上面的结果。

    来一段代码验证下:

    <?php
    
    $arr1 = [1,2,3,4];
    
    foreach ($arr1 as  &$item) {
        //do nothing
    }
    
    $arr2 = ['a','b','c','d'];
    
    echo '<pre>';
    foreach ($arr2 as $item) {
        print_r($arr1);
    }
    

    输出结果:

    Array
    (
        [0] => 1
        [1] => 2
        [2] => 3
        [3] => a
    )
    Array
    (
        [0] => 1
        [1] => 2
        [2] => 3
        [3] => b
    )
    Array
    (
        [0] => 1
        [1] => 2
        [2] => 3
        [3] => c
    )
    Array
    (
        [0] => 1
        [1] => 2
        [2] => 3
        [3] => d
    )
    

    这里应该算是比较基础的点吧。但是因为对作用域范围不够敏感,踩了个坑还排查了半天(实际业务代码较多,开始没想到是这里的问题)。

    说下这里要注意的点吧

    1. foreach 时候的循环变量尽量不要用同一个变量,尤其是涉及到取引用的
    2. 循环变量取引用的,退出循环后,最好是unset掉,防止后面不小心改掉了该数据
  • 相关阅读:
    占德国与哥斯达黎加
    晕,终于见识到了J2me的代码容量限制
    使用Adobe Acrobat SDK 需注意的要点
    看到一窝火的对联
    Entity Framework 学习初级篇4Entity SQL(转)
    Entity Framework 学习初级篇6EntityClient(转)
    ASP.NET MVC3 快速入门第三节 添加一个视图(转)
    ASP.NET MVC3 快速入门第一节 概述(转)
    Entity Framework 学习初级篇1EF基本概况(转)
    PB TreeView 查找节点(转)
  • 原文地址:https://www.cnblogs.com/clannadxr/p/11368403.html
Copyright © 2011-2022 走看看