浅谈PHP中关于foreach使用引用变量的坑

写PHP好多年,但仍然会犯低级错误,今天遇到个 foreach中引用变量时的坑,PHP版本为 5.6.12 代码如下:

<?php
$arr = ['a', 'b', 'c', 'd', 'e'];
foreach ($arr as $i=>&$a) {
  $a = $a.'_'. $a;
  echo $a .'<br>';
}
echo '<hr>';
foreach ($arr as $i=>$a) {
  echo $a .'<br>';
}
echo '<hr>';
print_r($arr);

输出结果

一开始看到第二个 foreach 输出的结果感觉很是莫名其妙,怎么会输出两个 d_d 呢?

仔细想了想,原来因为PHP foreach 中的 $a 的作用域是整个函数的局部变量,在循环外部仍然有效,而不是被封闭在循环内的,

所以当执行第二个foreach 时的 $a 并不是新的变量,而是仍然指向 $arr 数组第5个元素的地址引用,

当第二个 foreach 在循环时实际上是在不停的给 $arr 数组的第5个元素赋值,

具体赋值情况,

第一次:a_a 赋值给第5个元素, 结果为: [a_a, b_b, c_c, d_d,a_a]

第二次:b_b 赋值给第5个元素,结果为: [a_a, b_b, c_c, d_d,b_b]

第三次:c_c 赋值给第5个元素,结果为: [a_a, b_b, c_c, d_d,c_c]

第四次:d_d 赋值给第5个元素,结果为: [a_a, b_b, c_c, d_d,d_d]

第五次:此时因为第五个元素已经变成 d_d 又重新把 d_d 赋值给第5个元素,结果还是为: [a_a, b_b, c_c, d_d,d_d]

解决办法:

1.尽量不使用相同的循环变量名;

2.每次使用完或再次使用前进行 unset($a); 处理,解除地址应用

还是用上面代码示例:

$arr = ['a', 'b', 'c', 'd', 'e'];
foreach ($arr as $i=>&$a) {
  $a = $a.'_'. $a;
  echo $a .'<br>';
}
echo '<hr>';
echo $a;
echo '<hr>';

// 这里 unset 掉
unset($a);

echo $a = 'ccc';
echo '<hr>';
print_r($arr);
echo '<hr>';
foreach ($arr as $i=>$a) {
  echo $a .'<br>';
}
echo '<hr>';
print_r($arr);

输出结果:

现在就正常了,这些小细节一定要注意了

以上就是小编为大家带来的浅谈PHP中关于foreach使用引用变量的坑全部内容了,希望大家多多支持我们~

(0)

相关推荐

  • PHP中foreach()用法汇总

    PHP 4 引入了 foreach 结构,和 Perl 以及其他语言很像.这只是一种遍历数组简便方法.foreach 仅能用于数组,当试图将其用于其它数据类型或者一个未初始化的变量时会产生错误.有两种语法,第二种比较次要但却是第一种的有用的扩展. foreach (array_expression as $value) statement foreach (array_expression as $key => $value) statement 第一种格式遍历给定的 array_express

  • PHP模板引擎Smarty内建函数foreach,foreachelse用法分析

    本文实例讲述了PHP模板引擎Smarty内建函数foreach,foreachelse用法.分享给大家供大家参考,具体如下: 在 Smarty 模板中,您可以使用 foreach 来重复一个区块.而在模板中则需要从 PHP 中分配过来一个数组.这个数组可以是多维数组.Smarty 中 {foreach} 标记和 PHP 中 foreach 相同,不同的是它们的一个在模板文件中使用,一个在 PHP 脚本中使用.因此,语法会不同.但是,它们的作用都是相同的,即遍历数组中的内容.与 {foreach}

  • PHP中使用foreach()遍历二维数组的简单实例

    第一种类型 想用foreach()遍历整个二维数组: $team = array('lk','ok'); $book = array('linux服务器配置与管理',$team); foreach($book as $k=>$val) //for $book each $value( as ) echo $k.'=>'.$val.''; 输出结果是: 0=>linux服务器配置与管理 1=>Array 当然,其实我是想要所有具体内容,而不是输出array... 所以应该采用如下做法

  • PHP 数组遍历foreach语法结构及实例

    foreach() PHP foreach() 语法结构用于遍历操作或输出数组,foreach() 仅能用于遍历数组或对象,当试图将其用于其它数据类型或者一个未初始化的变量时会产生错误. 语法: foreach (array as $value) statement // 或者: foreach (array as $key => $value) statement 上述语法中,每次循环将当前单元的值赋给 $value 并且数组内部的指针向前移一步.在第二种语法格式中还将当前单元的键名也会在每次

  • php中使用in_array() foreach array_search() 查找数组是否包含时的性能对比

    判断某字符是否包含与某于数组中,方法有很多,刚学习php的新手们估计偏向于使用循环来解决,对于一般的小网站来说,这种解决方案是不会出现什么大问题的.但就性能来说,这种方法不是最好的方法,下面笔者就 foreach,in_array() array_search 这三种方法来比较这三种方法在性能表现上的差异. <?php $runtime= new runtime; $runtime->start(); $a = 'k'; $b = array('a','b','c','d','e','f','

  • 浅谈PHP中foreach/in_array的使用

    php在开发效率很高,这是无可厚非的,但是却是在牺牲执行效率的.php数组功能非常强大,但是也要多加考虑,多试几种情况情况,以防万一,这里,我就简单的说两个遇到的坑,以后如果有发现更多的,再补上吧! foreach 提供了遍历数组的简单方式,可以很方便的读取到数据或对象的内容,但是官方文档说了,由于 foreach 依赖内部数组指针,在循环中修改其值将可能导致意外的行为.所以,基本上, 1.不要想在循环内部修改里面的值,否则结果将超出你想要的: 2.使用'&'是一个安全的方式,虽然很少用到,但是

  • PHP循环遍历数组的3种方法list()、each()和while总结

    ①each()函数 each()函数需要传递一个数组作为参数,返回数组中当前元素的键/值对,并向后移动数组指针到下一个元素的位置.键/值对被返回带有4个元素的关联和索引混合的数组,键名分别为0.1.key和value.其中键名0和key对应的值是一样的,是数组元素的键名,1和value则包含有数组元素的值.如果内部指针越过了数组的末端,则each()返回FALSE.each()函数的使用如下所示: 复制代码 代码如下: <?php $contact = array("ID" =&

  • php下foreach提示Warning:Invalid argument supplied for foreach()的解决方法

    本文实例讲述了php下foreach()错误提示Warning: Invalid argument supplied for foreach() 的解决方法.分享给大家供大家参考.具体实现方法如下: 一.问题: php下foreach()错误提示Warning: Invalid argument supplied for foreach() 错误提示:Warning: Invalid argument supplied for foreach() in E:wampwwwmyshopcart.p

  • php each 返回数组中当前的键值对并将数组指针向前移动一步实例

    each函数返回数组中当前的键/值对并将数组指针向前移动一步 基本语法 array each ( array &$array ) 在执行 each() 之后,数组指针将停留在数组中的下一个单元或者当碰到数组结尾时停留在最后一个单元.如果要再用 each 遍历数组,必须使用 reset() . 参数介绍: 参数 描述 array 必需.规定要使用的数组. each() 函数生成一个由数组当前内部指针所指向的元素的键名和键值组成的数组,并把内部指针向前移动. 返回值: 返回 array 数组中当前指

  • 浅谈PHP中关于foreach使用引用变量的坑

    写PHP好多年,但仍然会犯低级错误,今天遇到个 foreach中引用变量时的坑,PHP版本为 5.6.12 代码如下: <?php $arr = ['a', 'b', 'c', 'd', 'e']; foreach ($arr as $i=>&$a) { $a = $a.'_'. $a; echo $a .'<br>'; } echo '<hr>'; foreach ($arr as $i=>$a) { echo $a .'<br>'; } e

  • 浅谈Java中的四种引用方式的区别

    强引用.软引用.弱引用.虚引用的概念 强引用(StrongReference) 强引用就是指在程序代码之中普遍存在的,比如下面这段代码中的object和str都是强引用: Object object = new Object(); String str = "hello"; 只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象. 比如下面这段代码: public class Main { publi

  • 浅谈vue中使用编辑器vue-quill-editor踩过的坑

    结合vue+element-ui+vue-quill+editor二次封装成组件 1.图片上传 分析原因 项目中使用vue-quill-editor富文本编辑器,在编辑内容的时候,我们往往会编辑图片,而vue-quill-editor默认的处理方式是直接将图片转成base64格式,导致上传的内容十分庞大,且服务器接受post的数据的大小是有限制的,很有可能就提交失败,造成用户体验差. 引入element-ui 编辑editor.vue文件 <template> <div> <

  • 浅谈js中同名函数和同名变量的执行问题

    经测试未写成闭包形式的在同一个文件中或者不同的 js 文件中定义的同名函数,调用时会执行后面一个定义的函数.即使这样写也会执行后面一个即会弹出2: <script type="text/javascript"> function t(){ alert(1); } t(); function t(){ alert(2); } </script> 另外,定义的变量与css样式也是以后面的为准. 但是对于函数,经测试这样写却会执行前面的函数直接量即弹出1,暂时不知道是

  • 浅谈Django中的QueryDict元素为数组的坑

    一般在Django的视图函数中使用request.POST来获取请求体,request.POST是QueryDict类,通常作为dict来使用. 正常如下图 但是昨天在使用的时候遇到一个错误,提示从QueryDict里面pop出来的值类型为list. 一脸懵逼 在命令行敲代码,发现了这个坑, 如下图 可以看到,pop出来的值被放在的一个list里面.关键这个不同版本之间,行为还有所不同,就是因为在开发机器上一切正常,到了测试服务器就出问题才被发现的. 知道了问题,解决起来也简单,直接调用Quer

  • 浅谈正则表达式中的分组和引用实现方法

    问题 在外刊君读者群中看到有人提出这样的一个需求: 把字符串切成连续相同字符的正则怎么写?比如abbcccdddd切成a,bb,ccc,dddd 之前我对正则表达式也是略有研究,想尝试一下.其实我对正则表达式的学习基本完全来源于犀牛书的第10章,真正看懂这一章,我觉得操作正则表达式应该不在话下. 我的答案 先给出我的答案吧: 'abbccddd'.match(/(\w)\1*/g) // ["a", "bb", "cc", "ddd&q

  • 浅谈php中的循环while、do...while、for、foreach四种循环

    php中的while循环,循环执行代码块制定的次数,或者当指定的条件为真时循环执行代码块. ------------------------------------------------------------- 在我们编写代码是时候,我们经常需要一块代码块重复执行多次.我们就可以使用while循环语句来完成这个任务. while--只要指定条件成立,则循环执行代码块. do...while--首先执行一次代码块,然后在指定的条件成立时重复这个循环. for--循环执行代码块制定的次数. fo

  • 浅谈js中的引用和复制(传值和传址)

    好像一般很少人讲到js中的引用和复制,不过弄清楚这个概念可以帮助理解很多东西 先讲一下很基础的东西,看看js中几种数据类型分别传的什么 引用:对象.数组.函数 复制:数字.布尔 字符串单独说明,因为它的特殊性,无法确定是传递引用还是复制数值(因为字符串的值是没法改变的,所以纠结这个问题也是没意义的)但是用于比较的时候显然是属于传值比较(稍后具体说比较的事) 下面讲一下在使用中的具体体现 最普通的使用就是赋值了 var a = 1; var b = a; //赋的是a的复制值 b ++; aler

  • 浅谈Java中的克隆close()和赋值引用的区别

    学生类Student: package 克隆clone; /*要克隆必须实现这个借口:Cloneable,以标记这个对象可以克隆 Cloneable:此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制. 这个接口是标记接口,告诉我们实现该接口的类就可以实现对象的复制了. */ public class Student implements Cloneable { private String name; private int ag

  • 浅谈Java中对类的主动引用和被动引用

    本文研究的主要是Java中类的主动引用和被动引用,具体介绍如下. 主动引用,这里介绍的是主动引用的五种场景 1.遇到new,getstatic,putstatic,invokestatic这4条字节码指令时,类如果没初始化就会被初始化,创建对象,读取或设置静态字段,调用静态方法. 2.反射 3.子类初始化前会先初始化父类 4.包含main方法的类,虚拟机启动时会先初始化该类 5.使用jdk的动态语言支持时(不明) 被动引用: class SuperClass{ static{ syso("sup

随机推荐