PHP关于foreach复制知识点总结

PHP的foreach是一个非常整洁和切中要害的语言结构。仍然有些人不喜欢使用它,因为他们认为它是缓慢的。一个通常命名的原因是foreach复制它迭代的数组。

因此,一些人建议写:

$keys = array_keys($array);
$size = count($array);
for ($i = 0; $i < $size; $i++) {
  $key  = $keys[$i];
  $value = $array[$key];

  // ...
}

而不是更直观和直接:

foreach ($array as $key => $value) {
  // ...
}

这里有两个问题:

Microoptimization是不好的。通常,它只会浪费您的时间,不会带来任何可度量的性能改进。

foreach的复制行为比大多数人认为的要复杂一些。通常情况下,“优化”的版本会比原始版本慢。

foreach什么时候复制?

foreach是否复制数组以及复制的数量取决于三件事:

是否引用了迭代数组、它的refcount有多高以及迭代是否通过引用完成。

没有引用,refcount == 1

在下面的代码中,$array没有被引用,并且refcount为1。在这种情况下,foreach不会复制数组(证明)——这与流行的观点相反,即foreach总是复制没有引用的迭代数组。

test();
function test() {
  $array = range(0, 100000);
  foreach ($array as $key => $value) {
    // ...
  }
}

原因很简单:为什么要这样做?foreach修改$array的唯一地方是它是内部数组指针。这是预期的行为,因此不需要预防。

未引用,refcount > 1

下面的代码看起来非常类似于前面的代码。唯一的区别是数组现在作为参数传递。这似乎是一个无关紧要的区别,但它确实改变了foreach的行为:

它现在将复制数组结构,而不是值(证明;如果你想知道这只是复制的结构,比较一下这个和那个脚本。第一个只复制结构,第二个两个都复制)。

$array = range(0, 100000);
test($array);
function test($array) {
  foreach ($array as $key => $value) {
    // ...
  }
}

乍一看这可能有点奇怪:

为什么当数组通过参数传递时,它会复制,但如果它是在函数中定义的,它就不会复制了?原因是数组zval现在在多个变量之间共享:函数外部的$array变量和函数内部的$array变量。如果foreach在不复制数组结构的情况下迭代数组,那么它不仅会改变函数中$array变量的数组指针,还会改变函数外$array变量的指针。因此foreach需要复制数组结构(即散列表)。另一方面,这些值仍然可以共享zvals,因此不需要复制。

引用

下一种情况与前一种情况非常相似。唯一的区别是数组是通过引用传递的。在这种情况下,数组将不会被复制(证明)。

$array = range(0, 100000);
test($array);
function test(&$array) {
  foreach ($array as $key => $value) {
    // ...
  }
}

在这种情况下,相同的推理适用于前一种情况:外部$数组和内部$数组共享zvals。不同的是,它们现在是引用(isref == 1),因此在这种情况下,对内部数组的任何更改都将对外部数组进行。所以如果内部数组的数组指针改变了,外部数组的数组指针也应该改变。这就是foreach不需要复制的原因。

迭代通过引用

上面的例子都是按值迭代的。对于引用迭代,应用相同的规则,但是附加值引用更改数组值的复制行为(关于结构复制的行为保持不变)。

情况“未引用,refcount == 1”没有改变。引用迭代意味着如果$值有任何变化,我们想要改变原始数组,这样数组就不会被复制(证明)。

“被引用”的情况也保持不变,在这种情况下,对$value的更改应该会更改引用迭代数组的所有变量(证明)。

只有“未引用,refcount > 1”的情况发生了变化,因为现在需要复制数组结构及其值。数组结构,因为否则函数外部的$array变量的数组指针会改变,而对$value的改变也会改变外部的$array值(证明)。

总结

当且仅当迭代数组未被引用且具有refcount > 1时,foreach将复制数组结构

foreach还将复制数组值,前提是且仅当上一个点应用并且迭代是通过引用完成时

(0)

相关推荐

  • PHP在弹框中获取foreach中遍历的id值并传递给地址栏

    1.php有时候我们需要再弹框中获取foreach中遍历的数据(例如id),在弹框中点击按钮并传递给地址栏跳转.那么应该怎么做呢. 2. 点击取现按钮,如果没有设置密码->弹框 3. 点击去设置,把用户名通过地址栏传递给别的页面. 4.使用onclick事件,把参数charge传递给function函数.function为弹窗函数. 5. 把username值传递过来.并给"去设置"赋值herf属性. 6. <div class="mask" >&

  • 浅谈PHP中关于foreach使用引用变量的坑

    写PHP好多年,但仍然会犯低级错误,今天遇到个 foreach中引用变量时的坑,PHP版本为 5.6.12 代码如下: <?php $arr = ['a', 'b', 'c', 'd', 'e']; foreach ($arr as $i=>&$a) { $a = $a.'_'. $a; echo $a .'<br>'; } echo '<hr>'; foreach ($arr as $i=>$a) { echo $a .'<br>'; } e

  • PHP中for循环与foreach的区别

    for循环与foreach的区别 foreach 依赖 IEnumerable. 第一次 var a in GetList() 时调用 GetEnumerator 返回第一个对象并赋给a, 以后每次再执行 var a in GetList() 的时候调用 MoveNext.直到循环结束. 期间GetList()方法只执行一次. + View Code for 循环靠下标定位.    list[3] 相当于 *(list + 3). + View Code or 循环每次循环会调用 GetCoun

  • PHP foreach遍历多维数组实现方式

    介绍 正常我们的foreach可以按顺序把一维数组里面每个 key => value 打印出来,但是如果是多维数组则需要循环在嵌套循环,或则递归实现,但是这些方式都不够灵活,因为在不确定该数组是几维的情况下,不可能永无止境的嵌套循环,如果采用递归到可以解决,但是如果只想使用foreach全部循环出来该如何实现? 实现方式 一 采用PHP本身自带的迭代器类 RecursiveIteratorIterator $test_arr = array(1,2,3,array(4,'aa'=>5,6,ar

  • PHP运用foreach神奇的转换数组(实例讲解)

    要求: 将二维数组$arr转换为以'time'和'type'为下标.'data'为值的二维数组: 原数组: $arr = array( 0 => array( 'data' => 100, 'type' => 1, 'time' => '2018-01-26', ), 1 => array( 'data' => 200, 'type' => 2, 'time' => '2018-01-26', ), 2 => array( 'data' => 3

  • PHP关于foreach复制知识点总结

    PHP的foreach是一个非常整洁和切中要害的语言结构.仍然有些人不喜欢使用它,因为他们认为它是缓慢的.一个通常命名的原因是foreach复制它迭代的数组. 因此,一些人建议写: $keys = array_keys($array); $size = count($array); for ($i = 0; $i < $size; $i++) { $key = $keys[$i]; $value = $array[$key]; // ... } 而不是更直观和直接: foreach ($arra

  • java中深复制知识点详解

    在正式开始深复制的讲解之前,我们先来理解一下概念.假设一个物品需要批量生产,但是这个物品还配有赠品,生产的时候需要把赠品也列在计划内.所谓深复制的原理就是这样,我们不能只复制属性,包括引用之类的附带也需要被复制.下面小编就为大家带来深复制的两种不同方法. 1.序列化实现 如下为谷歌Gson序列化HashMap,实现深度复制的例子: public class CopyDeepMapTest { public static void main(String[] args) { HashMap<Int

  • PHP 数组遍历方法大全(foreach,list,each)

    在PHP中数组分为两类: 数字索引数组和关联数组. 其中数字索引数组和C语言中的数组一样,下标是为0,1,2- 而关联数组下标可能是任意类型,与其它语言中的hash,map等结构相似. 下面介绍PHP中遍历关联数组的三种方法: 方法1:foreach 复制代码 代码如下: <?php $sports = array( 'football' => 'good', 'swimming' => 'very well', 'running' => 'not good'); foreach

  • javascript Array对象使用小结

    Javascript的数组实质是对象,它把数组的下标转换成字符串,用其作为属性,因此它明显比真正的数组慢,但它可以更方便地使用. 改变自身pop,push,reverse,shift,sort,splice,unshift, 不改变自身concat,join,slice,indexOf,lastIndexOf(后两个为1.6),1.6新增的迭代器:map,filter,forEach,every,some,1.8新增reduce,reduceRight Array 对象的方法 FF: Firef

  • Csh的基本语法介绍

    在*unix系统中,常用的shell有sh,bash,csh/tcsh, ksh. sh来自于systemV的Unix,是传统的Unix的shell,直到现在很多的系统管理员仍然喜欢使用sh. bash来自于BSD Unix,语法非常类似于C语言,所以通常有C/C++编程背景的开发人员最喜欢使用. ksh是对sh的扩展,且吸收了csh的一些有用的功能,但是由于开始ksh的license是AT&T,所以后来出现了很多的ksh的开源版本,例如mksh,pdksh等. bash是现在很多Linux的发

  • Lua教程(三):表达式和语句

    一.表达式: 1. 算术操作符:     Lua支持常规算术操作符有:二元的"+"."-"."*"."/"."^"(指数)."%"(取模),一元的"-"(负号).所有这些操作符都可用于实数.然而需要特别说明的是取模操作符(%),Lua中对该操作符的定义为:   复制代码 代码如下: a % b == a - floor(a / b) * b 由此可以推演出x % 1的

  • 深入理解PHP之数组(遍历顺序) Laruence原创

    经常会有人问我, PHP的数组, 如果用foreach来访问, 遍历的顺序是固定的么? 以什么顺序遍历呢? 比如: 复制代码 代码如下: <?php $arr['laruence'] = 'huixinchen'; $arr['yahoo'] = 2007; $arr['baidu'] = 2008; foreach ($arr as $key => $val) { //结果是什么? } 又比如: 复制代码 代码如下: <?php $arr[2] = 'huixinchen'; $arr

  • thinkphp循环结构用法实例

    本文实例讲述了thinkphp循环结构用法.分享给大家供大家参考.具体实现方法如下: 循环结构,在循环输出中变量不用加$符号 实例1.for 复制代码 代码如下: <table border='1' width='500'>      <for start='0' end='10' name='j' step='-2' comparison='gt'>//lt正序step是步调值加2 / gt倒序输出step是步调值减2          <tr><td>{

  • php遍历数组的方法分享

    在PHP中数组分为两类: 数字索引数组和关联数组. 其中数字索引数组和C语言中的数组一样,下标是为0,1,2- 而关联数组下标可能是任意类型,与其它语言中的hash,map等结构相似. 方法1:foreach 复制代码 代码如下: <?php $sports = array( 'football' => 'good', 'swimming' => 'very well', 'running' => 'not good'); foreach ($sports as $key =>

  • 3个PHP多维数组转为一维数组的方法实例

    很多时候我们需要将多维数组转成一维数组,因为我们只需要一维数组,而且一维数组使用起来更方便,在PHP中如何将多维数组转成一维数组?下面我们来看看三个多维数组转为一维数组例子:一.使用foreach 复制代码 代码如下: <?php   function arr_foreach ($arr)    {      static $tmp=array();        if (!is_array ($arr))       {         return false;      }      fo

随机推荐