PHP关于foreach复制知识点总结


Posted in PHP onJanuary 28, 2019

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还将复制数组值,前提是且仅当上一个点应用并且迭代是通过引用完成时

PHP 相关文章推荐
Discuz 5.0 中读取纯真IP数据库函数分析
Mar 16 PHP
dede3.1分页文字采集过滤规则详说(图文教程)
Apr 03 PHP
简单的PHP缓存设计实现代码
Sep 30 PHP
PHP程序漏洞产生的原因分析与防范方法说明
Mar 06 PHP
mysql_connect localhost和127.0.0.1的区别(网络层阐述)
Mar 26 PHP
Zend Framework框架Smarty扩展实现方法
Mar 22 PHP
php文件上传后端处理小技巧
May 22 PHP
php禁用函数设置及查看方法详解
Jul 25 PHP
PHP文件操作实例总结
Sep 27 PHP
centos下file_put_contents()无法写入文件的原因及解决方法
Apr 01 PHP
Laravel框架执行原生SQL语句及使用paginate分页的方法
Aug 17 PHP
php封装的page分页类完整实例代码
Feb 01 PHP
实例讲解PHP验证邮箱是否合格
Jan 28 #PHP
PHP将英文数字转换为阿拉伯数字实例讲解
Jan 28 #PHP
PHP实现一个轻量级容器的方法
Jan 28 #PHP
PDO::_construct讲解
Jan 27 #PHP
PDO::commit讲解
Jan 27 #PHP
PDO::beginTransaction讲解
Jan 27 #PHP
PHP的PDO大对象(LOBs)
Jan 27 #PHP
You might like
PHP url 加密解密函数代码
2011/08/26 PHP
解析PHP中的unset究竟会不会释放内存
2013/07/18 PHP
js+php实现静态页面实时调用用户登陆状态的方法
2015/01/04 PHP
比较详细的关于javascript中void(0)的具体含义解释
2007/08/02 Javascript
网页开发中的容易忽略的问题 javascript HTML中的table
2009/04/15 Javascript
用JSON做数据传输格式中的一些问题总结
2011/12/21 Javascript
在JavaScript并非所有的一切都是对象
2013/04/11 Javascript
JS实现简单的Canvas画图实例
2013/07/04 Javascript
7个jQuery最佳实践
2016/01/12 Javascript
深入理解JavaScript中的浮点数
2016/05/18 Javascript
JSON字符串和对象相互转换实例分析
2016/06/16 Javascript
基于jQuery实现左侧菜单栏可折叠功能
2016/12/27 Javascript
BootStrap 动态表单效果
2017/06/02 Javascript
laydate日历控件使用方法详解
2017/11/20 Javascript
JS运动特效之完美运动框架实例分析
2018/01/24 Javascript
nodejs简单抓包工具使用详解
2019/08/23 NodeJs
vue中@change兼容问题详解
2019/10/25 Javascript
[01:06]DOTA2小知识课堂 Ep.01 TP出门不要忘记帮队友灌瓶哦
2019/12/05 DOTA
Python内置函数bin() oct()等实现进制转换
2012/12/30 Python
python计算N天之后日期的方法
2015/03/31 Python
Python中循环后使用list.append()数据被覆盖问题的解决
2018/07/01 Python
Python写一个基于MD5的文件监听程序
2019/03/11 Python
Python实例方法、类方法、静态方法的区别与作用详解
2019/03/25 Python
Python 矩阵转置的几种方法小结
2019/12/02 Python
Python 简单计算要求形状面积的实例
2020/01/18 Python
用html5绘制折线图的实例代码
2016/03/25 HTML / CSS
解释下列WebService名词:WSDL、SOAP、UDDI
2012/06/22 面试题
会计岗位职责模板
2014/03/12 职场文书
婚礼主持词
2014/03/13 职场文书
法律六进活动方案
2014/03/13 职场文书
医疗器械售后服务承诺书
2014/05/21 职场文书
大学生创业计划书
2014/08/14 职场文书
教师辞职信范文
2015/02/28 职场文书
小孩不笨观后感
2015/06/03 职场文书
2015年秋季小学开学标语
2015/07/16 职场文书
python基础之爬虫入门
2021/05/10 Python