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 相关文章推荐
详解:――如何将图片储存在数据库里
Dec 05 PHP
php获取mysql数据库中的所有表名的代码
Apr 23 PHP
有关phpmailer的详细介绍及使用方法
Jan 28 PHP
PHP strstr 函数判断字符串是否否存在的实例代码
Sep 28 PHP
php使用fsockopen函数发送post,get请求获取网页内容的方法
Nov 15 PHP
PHP实现服务器状态监控的方法
Dec 09 PHP
php实现转换html格式为文本格式的方法
May 16 PHP
基于thinkPHP类的插入数据库操作功能示例
Jan 06 PHP
PHP开发APP端微信支付功能
Feb 17 PHP
thinkPHP简单导入和使用阿里云OSSsdk的方法
Mar 15 PHP
Laravel框架实现redis集群的方法分析
Sep 14 PHP
PHP中mysqli_get_server_version()的实例用法
Feb 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正则
2006/07/07 PHP
phpmail类发送邮件函数代码
2012/02/20 PHP
PHP Warning: PHP Startup: Unable to load dynamic library \ D:/php5/ext/php_mysqli.dll\
2012/06/17 PHP
PHP中md5()函数的用法讲解
2019/03/30 PHP
Laravel5.7 数据库操作迁移的实现方法
2019/04/12 PHP
php 中self,this的区别和操作方法实例分析
2019/11/04 PHP
PHP利用缓存处理用户注册时的邮箱验证,成功后用户数据存入数据库操作示例
2019/12/31 PHP
用javascript getComputedStyle获取和设置style的原理
2008/10/10 Javascript
Javascript和Ajax中文乱码吐血版解决方案
2009/12/21 Javascript
JavaScript 拾漏补遗
2009/12/27 Javascript
基于jQuery实现的当离开页面时出现提示的实现代码
2011/06/27 Javascript
jQuery EasyUI API 中文文档 - NumberSpinner数值微调器使用介绍
2011/10/21 Javascript
JQuery 操作/获取table具体代码
2013/06/13 Javascript
JavaScript Split()方法
2015/12/18 Javascript
Javascript基础_嵌入图像的简单实现
2016/06/14 Javascript
微信JS接口大全
2016/08/25 Javascript
详解小程序用户登录状态检查与更新实例
2019/05/15 Javascript
vue远程加载sfc组件思路详解
2019/12/25 Javascript
JS继承实现方法及优缺点详解
2020/09/02 Javascript
[01:08:44]NB vs VP 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Linux 下 Python 实现按任意键退出的实现方法
2016/09/25 Python
python 查找字符串是否存在实例详解
2017/01/20 Python
Python rstrip()方法实例详解
2018/11/11 Python
Pyqt5如何让QMessageBox按钮显示中文示例代码
2019/04/11 Python
详解在Python中以绝对路径或者相对路径导入文件的方法
2019/08/30 Python
Python 类方法和实例方法(@classmethod),静态方法(@staticmethod)原理与用法分析
2019/09/20 Python
使用Python爬取弹出窗口信息的实例
2020/03/14 Python
PHP基于phpqrcode类库生成二维码过程解析
2020/05/28 Python
python实现AHP算法的方法实例(层次分析法)
2020/09/09 Python
Selenium 配置启动项参数的方法
2020/12/04 Python
css3新单位vw、vh的使用教程
2018/03/23 HTML / CSS
Boden美国官网:英伦原创时装品牌
2017/07/03 全球购物
DNA测试:Orig3n
2019/03/01 全球购物
银行出纳岗位职责
2013/11/25 职场文书
2015年暑假工作总结
2015/07/13 职场文书
聘任书范文大全
2015/09/21 职场文书