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 相关文章推荐
php中使用parse_url()对网址进行解析的实现代码(parse_url详解)
Jan 03 PHP
APACHE的AcceptPathInfo指令使用介绍
Jan 18 PHP
浅析php数据类型转换
Jan 09 PHP
php中实现获取随机数组列表的自定义函数
Apr 02 PHP
Yii2框架实现注册和登录教程
Sep 30 PHP
php实现文件与16进制相互转换的方法示例
Feb 16 PHP
php查找字符串中第一个非0的位置截取
Feb 27 PHP
php+mysql+jquery实现简易的检索自动补全提示功能
Apr 15 PHP
php实现与python进行socket通信的方法示例
Aug 30 PHP
基于CI(CodeIgniter)框架实现购物车功能的方法
Apr 09 PHP
php+websocket 实现的聊天室功能详解
May 27 PHP
TP3.2框架分页相关实现方法分析
Jun 03 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多例模式介绍
2013/06/24 PHP
PHP中使用break跳出多重循环代码实例
2015/01/21 PHP
php实现的农历算法实例
2015/08/11 PHP
Python中使用django form表单验证的方法
2017/01/16 PHP
jquery 注意事项与常用语法小结
2010/06/07 Javascript
jquery photoFrame 图片边框美化显示插件
2010/06/28 Javascript
说说JSON和JSONP 也许你会豁然开朗
2012/09/02 Javascript
jquery退出each循环的写法
2014/02/26 Javascript
JS实现兼容性好,自动置顶的淘宝悬浮工具栏效果
2015/09/18 Javascript
js仿支付宝填写支付密码效果实现多方框输入密码
2016/03/09 Javascript
如何用JavaScript实现动态修改CSS样式表
2016/05/20 Javascript
将json转换成struts参数的方法
2016/11/08 Javascript
angularjs中ng-attr的用法详解
2016/12/31 Javascript
原生js FileReader对象实现图片上传本地预览效果
2020/03/27 Javascript
jQuery实现简单的回到顶部totop功能示例
2017/10/16 jQuery
利用nodeJs anywhere搭建本地服务器环境的方法
2018/05/12 NodeJs
jQuery+PHP实现上传裁剪图片
2020/06/29 jQuery
vue移动端屏幕适配详解
2019/04/30 Javascript
利用Vue实现一个markdown编辑器实例代码
2019/05/19 Javascript
VUE 解决mode为history页面为空白的问题
2019/11/01 Javascript
jQuery实现点击滚动到指定元素上的方法分析
2020/03/19 jQuery
react国际化化插件react-i18n-auto使用详解
2020/03/31 Javascript
jQuery实现回到顶部效果
2020/10/19 jQuery
ES5和ES6中类的区别总结
2020/12/21 Javascript
Python 装饰器深入理解
2017/03/16 Python
详解python破解zip文件密码的方法
2020/01/13 Python
Python Numpy库常见用法入门教程
2020/01/16 Python
python爬虫把url链接编码成gbk2312格式过程解析
2020/06/08 Python
Python中三维坐标空间绘制的实现
2020/09/22 Python
英国剑桥包中文官网:The Cambridge Satchel Company中国
2018/11/06 全球购物
Oracle性能调优原则
2012/05/03 面试题
应届大学生自荐信格式
2013/09/21 职场文书
2014年卫生保健工作总结
2014/12/08 职场文书
教育实习指导教师评语
2014/12/31 职场文书
竞选稿之小学班干部
2019/10/31 职场文书
原生Js 实现的简单无缝滚动轮播图的示例代码
2021/05/10 Javascript