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 相关文章推荐
层叠菜单的动态生成
Oct 09 PHP
判“新”函数:得到今天与明天的秒数
Oct 09 PHP
PHP面向对象的使用教程 简单数据库连接
Nov 25 PHP
Discuz 模板引擎的封装类代码
Jul 18 PHP
理解和运用PHP中的多态性[译]
Aug 02 PHP
php中使用redis队列操作实例代码
Feb 07 PHP
鸡肋的PHP单例模式应用详解
Jun 03 PHP
Ajax提交表单时验证码自动验证 php后端验证码检测
Jul 20 PHP
详解PHP原生DOM对象操作XML的方法
Oct 17 PHP
PHP有序表查找之二分查找(折半查找)算法示例
Feb 09 PHP
PHP使用XMLWriter读写xml文件操作详解
Jul 31 PHP
PHP图像处理 imagestring添加图片水印与文字水印操作示例
Feb 06 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 输出双引号&quot;与单引号'的方法
2010/05/09 PHP
php ucwords() 函数将字符串中每个单词的首字符转换为大写(实现代码)
2016/05/12 PHP
PHP实现自动识别原编码并对字符串进行编码转换的方法
2016/07/13 PHP
Laravel jwt 多表(多用户端)验证隔离的实现
2019/12/18 PHP
PHP7 list() 函数修改
2021/03/09 PHP
javascript自执行函数之伪命名空间封装法
2010/12/25 Javascript
基于JQuery的Select选择框的华丽变身
2011/08/23 Javascript
JQuery球队选择实例
2015/05/18 Javascript
Bootstrap前端开发案例二
2016/06/17 Javascript
Bootstrapvalidator校验、校验清除重置的实现代码(推荐)
2016/09/28 Javascript
微信小程序加载更多 点击查看更多
2016/11/29 Javascript
微信小程序 设置启动页面的两种方法
2017/03/09 Javascript
Angular4实现鼠标悬停3d倾斜效果
2017/10/25 Javascript
ionic3实战教程之随机布局瀑布流的实现方法
2017/12/28 Javascript
dts文件中删除一个node或属性的操作方法
2018/08/05 Javascript
Vuex 在Vue 组件中获得Vuex 状态state的方法
2018/08/27 Javascript
vue-cli history模式实现tomcat部署报404的解决方式
2019/09/06 Javascript
在Python的struct模块中进行数据格式转换的方法
2015/06/17 Python
使用Python编写简单的画图板程序的示例教程
2015/12/08 Python
Pycharm编辑器技巧之自动导入模块详解
2017/07/18 Python
python正则表达式面试题解答
2020/04/28 Python
Python读取txt文件数据的方法(用于接口自动化参数化数据)
2018/06/27 Python
python实现时间o(1)的最小栈的实例代码
2018/07/23 Python
详解python中递归函数
2019/04/16 Python
python利用wx实现界面按钮和按钮监听和字体改变的方法
2019/07/17 Python
pytorch 实现在一个优化器中设置多个网络参数的例子
2020/02/20 Python
Django框架models使用group by详解
2020/03/11 Python
Java如何基于wsimport调用wcf接口
2020/06/17 Python
只要五步 就可以用HTML5/CSS3快速制作便签贴特效(图)
2012/06/04 HTML / CSS
linux面试题参考答案(4)
2013/01/28 面试题
小学生演讲稿大全
2014/04/25 职场文书
城管执法人员纪律作风整顿思想汇报
2014/09/13 职场文书
授权委托书(公民个人适用)
2014/09/19 职场文书
金陵十三钗观后感
2015/06/04 职场文书
2016年秋季运动会加油稿
2015/12/21 职场文书
Java中API的使用方法详情
2022/04/06 Java/Android