【问题标题】:Php foreach- Why it doesn't override the array value while iterating?Php foreach-为什么它在迭代时不覆盖数组值?
【发布时间】:2012-09-07 06:47:27
【问题描述】:

我对 php foreach 迭代有疑问。

请看我下面的代码。

代码:

   $arr=array(1,2,3);

    echo '$arr value : '. $arr;

    echo '<br>';

    foreach($arr as $arr){
        echo $arr.'<br>';
    }
    echo '$arr value : '. $arr;

输出:

$arr value : Array
1
2
3
$arr value : 3

在迭代数组时,我使用相同的数组名称来赋值键 foreach($arr as $arr),但它工作正常。它是如何工作的?

为什么它在迭代时不覆盖数组值?

我想知道 foreach 迭代是如何工作的。

请帮助我!

提前致谢 洛根

【问题讨论】:

  • 这绝对是一个令人惊讶的输出。
  • php 不会以某种方式缓存原始 $arr(数组)的内容,然后在循环时,它会更改并显示 $arr(如 1、2 和 3),然后在最后 $ arr 保留为“3”,因为它只是不保存缓存的值,回到原始文件中,因为 php 不希望你覆盖它..
  • @PraveenKumar 请仔细检查我的问题
  • @loganphp 我也看到了。嗯,呃... :P 我没有答案。它处理 PHP 解释器本身的内部工作。 :)

标签: php foreach


【解决方案1】:

为什么它在迭代时不覆盖数组值?

foreach 将作用于原始数组的副本,因此您在 foreach 循环中更改的内容不会更改您正在循环的值。

【讨论】:

    【解决方案2】:

    PHP 使用copy on writelazy copy 机制和reference counting 进行内存处理。

    在foreach迭代的第一阶段,$arr被“软拷贝”(没有实际拷贝,只是增加了$arrayzvalrefcount)。结帐variable container and label 的 PHP 变量。

    在我们的例子中,

    • 它首先保持对实际$arr变量的引用,然后从引用点获取数组的第一个值。
    • 供以后使用,第一个数组元素分配给第二个$arr foreach($arr as $arr)
    • 在下一次迭代中,从先前保存的参考点获取第二个数组值,并将该值分配给相同的 $arr 并继续。
    • 由于$arr 的值在循环内更改,您无法使用$arr 变量在循环外打印该数组。

    希望你能理解……

    如需深入研究,请查看http://www.php.net/manual/en/internals2.opcodes.fe-fetch.phphttp://www.php.net/manual/en/internals2.opcodes.fe-reset.php

    有趣的是,你也可以玩这个......

    current() 在 foreach 循环中总是返​​回相同的元素!!!

    代码

    $source = array(10, 20, 30);
    foreach ($source as $value) {
        echo 'Value is ', $value, ', and current() is ', current($source), '<br>';
    }
    

    输出

    Value is 10, and current() is 20
    Value is 20, and current() is 20
    Value is 30, and current() is 20
    

    【讨论】:

      【解决方案3】:
      foreach ($arr as $arr) {
          // code
      }
      

      这可能会让您感到困惑,因为您对其工作原理的心智模型是:

      1. PHP 将当前元素从$arr 中取出并推进数组指针
      2. 它将值分配给$arr
      3. 它执行// code
      4. 从第一步开始重复

      它实际上做了什么(或至少是它的近似简化):

      1. PHP 启动foreach 操作,获取与$arr 关联的数组值
      2. 它把这个数组放在内部的某个地方,比如说var iterator
      3. 它从var iterator 获取当前元素并推进迭代器
      4. 它将它所取的值分配给脚本中的$arr
      5. 它执行// code
      6. 从第 3 步开始重复

      换句话说,它不会在每次迭代时从$arr 中获取下一个值,它只使用一次来获取初始迭代器。它迭代的实际内容存储在内部,不再与$arr 关联。这意味着$arr 在您的脚本中可免费用于其他目的,PHP 很乐意在每次迭代中重用它。循环完成后,最后一个元素保留在$arr

      如果您知道匿名函数,也许这可以更好地说明为什么它会以这种方式工作:

      foreach($arr, function ($arr) {
          // code
      });
      

      这样一个foreach函数的实现可以简单的这样:

      function foreach(array $array, callable $code) {
          while (list(, $value) = each($array))  {
              $code($value);
          }
      }
      

      【讨论】:

      • +1,除了你最后的说明性例子没有解释为什么$arr在循环之后被改变:-)
      • 嗯,是的,在匿名函数中,$arr 不会泄漏到周围的范围内。这确实是我认为最不复杂的事情,因为“循环变量在循环之后仍然可用并且具有最后一个值”无论变量名称如何,它的工作原理都是一样的...... :)
      【解决方案4】:

      $arr 和 $arr 在您的代码中是相同的。源数组和引用变量具有相同的名称。因此 foreach 保留上次收到的值,它不会放弃该变量。

      【讨论】:

        【解决方案5】:

        foreach使用原始数组的副本,所以你可以想代码

        foreach($arr as $arr){
            echo $arr.'<br>';
        }
        

        如下:

        for ($i = 0, $arr_tmp = $arr, $len = count($arr_tmp); $i < $len; $i++) {
          $arr = $arr_tmp[$i];
          echo $arr.'<br>';
        }
        

        这就解释了为什么$arr 最终是3

        【讨论】:

          【解决方案6】:

          当您获取记录时,您正在重写数组,您要求代码从 $arr 获取记录并将其放入名为 $arr 的数组中,因此您使用单个参数重写了整个数组 前 $arr = {1,2,3}; 在这条线和第一次迭代之后 foreach ($arr as $arr) 现在 $arr 等于 3 数组的最后一个元素,我希望你能理解这个问题

          【讨论】:

            【解决方案7】:

            嗯,经过一番调查,我想出了这个代码:

            <?php
            $arr=array(1,2,3);
            
            echo '$arr value : '. $arr;
            
            echo '<br>';
            
            foreach($arr as $arr){
                echo $arr.'<br>';
            }
            
            foreach($arr as $key) {
                echo $key.'<br>';
            }
            echo '$arr value : '. $arr;
            

            哪个有这个输出:

            $arr value : Array
            1
            2
            3
            PHP Warning:  Invalid argument supplied for foreach() in ...file...
            

            我对此的解读是,第二个 $arrforeach 循环内隐藏第一个,但一旦它退出 foreach 循环,它就会在内部取消设置符号 ($arr)

            【讨论】:

            • 它不会取消设置,它会用foreach 在循环中的最后一个值覆盖它。所以你第二个foreach 试图循环一个值,而不是一个数组
            • 没想到,更惨。
            【解决方案8】:

            foreach 在迭代其元素之前首先评估左侧。因此,对名称 $arr 的重新分配不会修改 $arr。

            此外,循环变量泄漏到外部上下文中,如documented:

            $value 的引用和最后一个数组元素即使在 foreach 循环之后仍然存在。建议通过 unset() 销毁。

            当然,为了避免混淆,你应该简单地为循环变量使用一个不同的名称,而不是你正在循环的数组:

            $arr=array(1,2,3);
            foreach($arr as $a) { // Note the "as $a", not "as $arr"
                echo $a.'<br>';
            }
            echo '$arr value : '. $arr;
            

            【讨论】:

            • 我认为这就是问题所在 - 为什么当变量具有相同名称时它会以这种方式工作。
            • @MarekKarbarz 修改了答案。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-06-20
            • 2021-08-10
            • 1970-01-01
            • 2013-03-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多