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下用GD生成生成缩略图的两个选择和区别
Apr 17 PHP
php中批量替换文件名的实现代码
Jul 20 PHP
PHP统计二维数组元素个数的方法
Nov 12 PHP
php数组去重实例及分析
Nov 26 PHP
ThinkPHP学习笔记(一)ThinkPHP部署
Jun 22 PHP
destoon实现商铺管理主页设置增加新菜单的方法
Jun 26 PHP
ThinkPHP里用U方法调用js文件实例
Jun 18 PHP
详解PHP中的PDO类
Jul 06 PHP
详解WordPress中给链接添加查询字符串的方法
Dec 18 PHP
Laravel框架实现调用百度翻译API功能示例
May 30 PHP
php 使用html5 XHR2实现上传文件与进度显示功能示例
Mar 03 PHP
PHP程序员简单的开展服务治理架构操作详解(一)
May 14 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数组中删除元素的实现代码
2012/06/22 PHP
简单的方法让你的后台登录更加安全(php中加session验证)
2012/08/22 PHP
php实现编辑和保存文件的方法
2015/07/20 PHP
基于thinkPHP3.2实现微信接入及查询token值的方法
2017/04/18 PHP
thinkphp5.1框架容器与依赖注入实例分析
2019/07/23 PHP
laravel利用中间件防止未登录用户直接访问后台的方法
2019/09/30 PHP
javascript 字符 Escape,encodeURI,encodeURIComponent
2009/07/09 Javascript
javascript 图片裁剪技巧解读
2012/11/15 Javascript
jqGrid随窗口大小变化自适应大小的示例代码
2013/12/28 Javascript
DOM基础教程之事件类型
2015/01/20 Javascript
JavaScript中的boolean布尔值使用学习及相关技巧讲解
2016/05/26 Javascript
Bootstrap table分页问题汇总
2016/05/30 Javascript
Vue 2.0中生命周期与钩子函数的一些理解
2017/05/09 Javascript
JavaScript之map reduce_动力节点Java学院整理
2017/06/29 Javascript
jQuery位置选择器用法实例分析
2019/06/28 jQuery
Vue.js数字输入框组件使用方法详解
2019/10/19 Javascript
jQuery实现简单QQ聊天框
2020/08/27 jQuery
python判断字符串编码的简单实现方法(使用chardet)
2016/07/01 Python
python判断字符串或者集合是否为空的实例
2019/01/23 Python
Python如何使用PIL Image制作GIF图片
2020/05/16 Python
Python 操作 MySQL数据库
2020/09/18 Python
html5实现完美兼容各大浏览器的播放器
2014/12/26 HTML / CSS
html5 figure和figcaption的使用方法
2018/09/10 HTML / CSS
美国照明、家居装饰和家具购物网站:Bellacor
2017/09/20 全球购物
数以千计的折扣工业产品:ESE Direct
2018/05/20 全球购物
Lookfantastic美国/加拿大:英国知名美妆购物网站
2019/03/27 全球购物
党校培训思想汇报
2013/12/30 职场文书
医药营销个人求职信范文
2014/02/07 职场文书
公司门卫工作职责
2014/06/28 职场文书
班级学习雷锋活动总结
2014/07/04 职场文书
2014年销售员工作总结
2014/12/01 职场文书
公司员工手册范本
2015/05/14 职场文书
观后感格式
2015/06/19 职场文书
2015年国庆晚会主持词
2015/07/01 职场文书
巾帼建功标兵先进事迹材料
2016/02/29 职场文书
python井字棋游戏实现人机对战
2022/04/28 Python