从一道面试题开始

在开始本节内容前,我们先来看看一道还算比较常见的PHP面试题:

1 $arr array('1','2','3');
2  
3 foreach($arr as &$v){
4 }
5  
6 foreach($arr as $v){
7 }
8  
9 var_dump($arr);

猜一下,运行的结果会是什么呢?熟悉PHP的同学可能已经知道结果了:

1 array
2   0 => string '1' (length=1)
3   1 => string '2' (length=1)
4   2 => &string '2' (length=1)
  •  
    奇怪了,为什么不是输出 1, 2, 3 呢?遍历操作也会改变原数组的值啊,我第一次听说呢。

是引用在捣鬼

那么为什么是1,2,2呢。让我们一步步来看:

我们知道对数组执行foreach循环时,是通过移动数组内部指针来实现的。对于上面的例子:当foreach循环结束的时候,由于$v为引用变量,所以$v 与 $arr[ 2 ] 指向了同一个地址空间(共享变量值),之后对$v的任何修改都会直接反映到数组$a中。

要不我们在程序中加入调试代码,看看运行过程的情况吧。

1 $arr array('1','2','3');
2  
3 foreach($arr as &$v){
4 }
5  
6 foreach($arr as $v){
7     var_dump($arr); 
8     echo "<br/>";
9 }

程序运行的结果是:

01 array
02   0 => string '1' (length=1)
03   1 => string '2' (length=1)
04   2 => &string '1' (length=1)
05  
06 array
07   0 => string '1' (length=1)
08   1 => string '2' (length=1)
09   2 => &string '2' (length=1)
10  
11 array
12   0 => string '1' (length=1)
13   1 => string '2' (length=1)
14   2 => &string '2' (length=1)

简单解释一下:

  1. 在第一次 foreach 循环里面,$v 是个引用。在循环结束之后,$v 与 $arr[2] = 3,指向了同一个内存块;
  2. 紧接着第二次循环,$v 引用并没有改变,还是$arr[2]的引用,这时 $v 值是 $arr[0] 的值,所以导致 $arr[2] = 1;
  3. 同上面,$v 已被 $arr[1] 影响,其值为 2,导致 $arr[2] = 2;
  4. 所以最终结果是 1, 2, 2.

关于引用,你需要了解的

1. 引用类似于指针,但是不同于指针。

下面的操作让 $a 和 $b 指向了同一个内存块,值为 “str”

1 $a "str";
2 $b = &$a;
3  
4 echo $a;
5 echo '<br />';
6 echo $b;

试下更改$a和$b中任何一个元素的值。另外一个值都为随之改变:

1 $a "str";
2 $b = &$a;
3  
4 $b "www.nowamagic.net";
5  
6 echo $a;
7 echo '<br />';
8 echo $b;

程序运行结果为:

1 www.nowamagic.net
2 www.nowamagic.net

2. 引用作为函数参数传递时,是可以被函数内部更改的:

01 $a "str";
02 $b = &$a;
03  
04 function change(&$a){ 
05     $a "www.nowamagic.net";
06
07  
08 change($a);
09  
10 echo $a;
11 echo '<br />';
12 echo $b;

程序运行结果为:

1 www.nowamagic.net
2 www.nowamagic.net

3. unset只会删除变量。并不会清空变量值对应的内存空间:

1 $a "str";
2 $b = &$a;
3  
4 unset($b);
5  
6 echo $a;
7 echo '<br />';
8 echo $b;

程序运行结果为:

1 str
2 Notice: Undefined variable: b
  •  
    PHP的引用有上面的特点,在编码的过程中,要小心使用引用。防止陷入莫名其妙的尴尬。PHP采用的复制机制是“引用计数,写时复制”,也就是说,即便在PHP里复制一个变量,最初的形式从根本上说其实仍然是引用的形式,只有当变量的内容发生变化时,才会出现真正的复制。所以才会出现上面的问题。之所以这么做是出于节省内存消耗得目的,同时也提升了复制的效率。

在 foreach 里使用引用要注意的陷阱(转)的更多相关文章

  1. CentOS磁盘用完的解决办法,以及Tomcat的server.xml里无引用,但是项目仍启动的问题

    这是我2018年的第一篇博客...人真是懒了啊...最近在写微信小程序,觉得小程序做的也... 好了不吐槽了,言归正传 前言: 由于我之前不是买了个三年的香港服务器么 , 之前广州2的服务器我就没有续 ...

  2. foreach里的按引用传值问题

    1.foreach($arr as $k=>&$v){ } 这样循环时候最后一个结果前边会有&,出现输出不了的情况,这时候只需要加一个unset($v),加在循环里和外均可. 2 ...

  3. <c:if>判断两个<c:forEach>里的数据是否相等

    问题:两个<c:forEach>嵌套,里面循环的值和外面的值进行比较(里层里的PARENTID是否等于外层的ID),如果相等就显示. <c:forEach items="$ ...

  4. [PHP] foreach循环的引用赋值可能导致的问题

    foreach($arr as &$value)1.引用赋值符号&,是每次循环的时候,把当前元素变成地址,$value变量就是对应元素的地址,循环结束$value是一个指向最后一个元素 ...

  5. php在foreach中使用引用赋值&可能遇到的问题(转)

    楼主在写项目的时候,由于初涉PHP的赋值引用操作,觉得这个功能非常强大,用时一时爽,没有深入了解过其中的原理,导致了一些当时觉得不可思议的BUG,废话不都说,我举个例子详细的描述一下这个问题. 代码: ...

  6. Python里的引用与拷贝规律

    python的可变不可变与各种浅拷贝深拷贝规则,一并梳理. Python一切皆引用 在C++/Java里,int a = 1就是创建变量为a,赋值为1:int b = a就是创建变量b,赋值为a的值. ...

  7. jsp页面中从forEach里向action里面传递其中的一个对象

    <c:forEach var="user" items="${users }"> <form action="user_update ...

  8. 如何获取c:forEach里面点击时候的值

    1.c:forEach遍历输出 <c:forEach items="${data}" var="item" > <a onclick=&quo ...

  9. 在mvc4里怎样引用:System.Web.Optimization和entityframework

    请在nuget 里运行: Install-Package Microsoft.AspNet.Web.Optimizationinstall-package entityframework

随机推荐

  1. Linux ./configure && make && make install 编译安装和卸载

    正常的编译安装/卸载: 源码的安装一般由3个步骤组成:配置(configure).编译(make).安装(make install).   configure文件是一个可执行的脚本文件,它有很多选项, ...

  2. 初涉JavaScript模式 (1) : 简介

    什么是模式? 广义上的模式是指 :在物体或事件上,产生的一种规律变化与自我重复的样式与过程.在模式之中,某些固定的元素不断以可预测的方式周期性重现.最基本而常见的模式,称为密铺,具备重复性以及周期性两 ...

  3. 拓扑排序-DFS

    拓扑排序的DFS算法 输入:一个有向图 输出:顶点的拓扑序列 具体流程: (1) 调用DFS算法计算每一个顶点v的遍历完成时间f[v] (2) 当一个顶点完成遍历时,将该顶点放到一个链表的最前面 (3 ...

  4. php基础知识【函数】(8)xml和变量函数

     一.XML函数 参数类型 data    --string,需要解析的数据集. parser  --resource,一个指向要取得字节索引的 XML 解析器的引用.  1.创建和释放XMl解析器 ...

  5. 批处理文件的@echo off是什么意思?

    @echo off 关闭回显 @echo on 打开回显 @echo off并不是DOS程序中的, 而是DOS批处理中的. 当年的DOS,所有操作都用键盘命令来完成, 当你每次都要输入相同的命令时, ...

  6. Plan-9效应:为什么东西不坏就不要去修它

    http://www.aqee.net/the-plan-9-effect-or-why-you-should-not-fix-it-if-it-aint-broken/ Plan-9是一个很棒的.很 ...

  7. 轻松解决Win8.1连接受限或无法连接WiFi问题

    在无线网络连接设置窗口中,找到当前连接的无线网络“WLAN状态”,右击查看“状态”. 在“WLAN状态”窗口中找到“无线属性”. 进入“无线网络属性”窗口,切换到“安全”页面,点击“高级设置”.最重要 ...

  8. BZOJ 1069 最大土地面积

    Description 在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大. Input 第1行一个正整数N,接下来N行,每行2个数x,y ...

  9. [Mon Feb 10 15:21:06 2014] [notice] child pid 7101 exit signal File size limit exceeded (25)

    今天遇到的问题: LAMP的LOG里报如下错误. 然后IE和FIREFOX里显示连接被重置或是无法访问. 但自己建一个正常的PHP测试探针倒可以. 原来是PHP错误日志太多,无法写入LOG导致. [r ...

  10. Android模拟器(出错问题)Intel X86 没法用!!!

    前提: CPU 支持 VT (Virtualization Technology), 而且仅限于 Intel CPU 首先要打开SDK Manager 下载intel haxm,下载位置: andro ...