10 Star 52 Fork 8

phpgod/phpgod

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
02.2.md 3.28 KB
一键复制 编辑 原始数据 按行查看 历史
开铭 提交于 7年前 . 更新 02.2.md

《PHP技术大全·第一卷》之你可能不知道的 PHP

foreach 细致解读

  • 常见问题
  1. foreach 中错误使用引用
<?php

$array1 = ["k1"=>1,"k2"=>2,"k3"=>3];
/*代码片段1*/
foreach($array1 as $k1=> &$v1)
{
    $v1 = $v1+1;
}
xdebug_debug_zval('array1');
//array1: (refcount=1, is_ref=1)=array ('k1' => (refcount=1, is_ref=1)=2, 'k2' => (refcount=1, is_ref=1)=3, 'k3' => (refcount=2, is_ref=1)=4)
//其中 refcount 表示引用计数,is_ref 表示是否为引用,0 表示不是引用,1 表示是引用
xdebug_debug_zval("v1");
//v1: (refcount=2, is_ref=1)=4

/*代码片段2*/
//其实上面的 foreach 内部相当于下面的代码片段,但是实际情况会复杂很多,这里只是类比
$array2 = ["k1"=>1,"k2"=>2,"k3"=>3];
$v2 = &$array2['k1'];//声明$v2变量是$array2['k1']的reference(译作:引用)
$v2 = $v2+1;
$v2 = &$array2['k2'];
$v2 = $v2+1;
$v2 = &$array2['k3'];
$v2 = $v2+1;
xdebug_debug_zval('array2');
//array2: (refcount=1, is_ref=0)=array ('k1' => (refcount=1, is_ref=1)=2, 'k2' => (refcount=1, is_ref=1)=3, 'k3' => (refcount=2, is_ref=1)=4)
xdebug_debug_zval("v2");
//v2: (refcount=2, is_ref=1)=4
//接下来我们应该把 $v2 变量 unset 掉,避免对 $array2['k3'] 的值产生副作用
//这时发现 $v2 成了未初始化的变量
unset($v2);
xdebug_debug_zval('v2');
//v2: (refcount=0, is_ref=0)=*uninitialized*

//我们再次给 $v2 赋值发现它已经非引用变量
$v2 = 111;
xdebug_debug_zval('v2');
//v2: (refcount=0, is_ref=0)=111

  1. 数组内部指针被玩坏
<?php
/*
php5 系列版本中,
foreach 使用了内部数组指针去遍历数组,
因此如果你在 foreach 内部使用了能够改变 foreach 内部数组指针的方法,例如:
reset($array):重置数组指针到初始位置0
next($array):数组指针移动到下一个
prev($array):数组指针移动到上一个
end($array):数组指针移动到最后一个,
这时我们的遍历数据可能会被打乱,
但在 PHP7 中由于 foreach 内部未使用内部数组指针,因此不会产生影响。
PHP5 和 PHP7 中,每次使用 foreach 遍历数组时都相当于调用了一次 reset 指针操作,让数组指针回到初始位置。
*/
/*代码片段3*/
$array = [1,2,3,4];

foreach ($array as $v)
{
    var_dump( $v);//php7依次输出:1,2,3,4 php5依次输出:1,2,3,4
    var_dump( next($array));//php7依次输出:2,3,4,false php5依次输出:3,4,false,false
}

  • 数组遍历为何 foreach 比 for 性能好

先看 stackOverflow 上的对比结果:Performance of FOR vs FOREACH in PHP, 主要有下面几点原因:

  1. PHP 中的数组 C 语言底层源码是由 HashTable 数据结构实现的,HashTable 的索引访问开销是 O(1) 级别,而 HashTable 这种数据结构适合 foreach 的 iterator(译作:迭代器)访问
  2. for循环需要维护一个 $i 计数器,且每次都要判断一下 $i 是否越界
  • 最佳实践
  1. 尽量使用 foreach,因为 for 可完全被 foreach 取代;
  2. 尽量不要在 foreach 内部使用指针操作函数;
  3. 在 foreach 中使用引用的方式修改数组值时一定要记得 unset 掉对应的中间变量。

目录 |上一节 |下一节

Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
PHP
1
https://gitee.com/nodestudy/phpgod.git
git@gitee.com:nodestudy/phpgod.git
nodestudy
phpgod
phpgod
master

搜索帮助