从一次面试经历谈PHP的普通传值与引用传值以及unset
关于这个概念一般都会在PHP的第一堂课说变量的时候给介绍,并且我以前还给其他PHPer介绍这个概念。但是作为一个工作一段时间的PHPer的我,竟然在面试的时候一下子拿不定主意最后还答错了,很觉得丢脸(下面我会一一道来),所以就写一篇关于这个概念的博文,该概念在PHP面试中也算是常考的题吧;
首先,要理解变量名存储在内存栈中,它是指向堆中具体内存的地址,通过变量名查找堆中的内存;
普通传值,传值以后,是不同的地址名称,指向不同的内存实体;
引用传值,传引用后,是不同的地址名称,但都指向同一个内存实体;改变其中一个,另外一个就也被改变;
以下我将通过三个列子来详细讲解这两个传值的区别:
Example1:
<?php
//普通传值
$param1=1;
$param2=2;
$param2 = $param1;
$param1 = 5; //变量1和变量2是两块内存,互不影响;
echo $param2; //所以此处还是显示为1
//引用传值 ↓↓
$param1=1;
$param2=2;
$param2 = &$param1; //把变量1的内存地址赋给变量2;此时的变量2和变量1全等;
echo $param2;// 1
$param1 = 5; //变量1和变量2是一处内存,改变其中一个,另外一个也被改变;
echo $param2; //显示为5
?>
Example2:
<?php
//函数中的普通传值 ↓↓
$param1 = 1;
function add($param2){
$param2=3;
}
$param3=add($param1); //调用方法add,并将变量1传给变量2,此处是普通传值,所以变量1和变量2是两处内存,互不影响;
echo '<br>$param1=='.$param1.'<br>'; //显示为$param1==1
echo '<br>$param2=='.$param2.'<!-- <br> -->'; //显示为$param2== 因为$param2是局部变量,函数运行完了以后就自动销毁,其不能影响全局
//函数中的引用传值 ↓↓ 注意,php不建议这样使用,并且php.in里面设置其会报错;
$param1 = 1;
function add($param2){
$param2=3;
return $param2;
}
$param3=add(&$param1); //调用方法add,并将变量1的引用传给变量2,此时两个地址指向同一内存,改变其中一个,另外一个也要被改变;
echo $param1; //3,内存已在函数内部改变;
echo $param3; //3
?>
Example3:
<?php
//给数组里面的键值各增加10;
$arr = array(3,5);
foreach($arr as $k=>$v){
$v+=10;//1.更改无效,相当于遍历出的键值扔给变量$v,然后更改变量$v的值,跟数组无关;
echo $v." ";//输出13 15;
}
foreach($arr as $k=>$v){
$arr[$k]+=10;//2.更改有效,直接更改键名里面的值;
echo $v;//输出3,5;
}
foreach($arr as &$v){
$v+=10;//3.更改有效,遍历的键值直接给了$v的地址,这个地址其实就是键名..$v+10就等于$arr[$k]+10;
}
?>
然后我们来看一下这道面试题:
$a = 1;
$b = &$a;
unset($a);
echo $b; //??
当时我的回答是这样的: 会报一个notice的错误,因为$b和$a共用一处内存,unset就把这处内存销毁掉了,然后输出$b变量的时候找不内存,所以应该是Notice: Undefined variable: b in
但是要注意: unset并没有真正销毁变量的作用...仅仅是切断了变量与内存之间的关系,内存只要还被引用着就不会被释放; $b和$a同时指向1,切断其中$a的关系,$b还是指向1,所以上题不报错,照样输出1。
另外补充一点: 在PHP中对象的传值默认是引用传值
再看一题:
在做这题之前我们回顾一下什么是析构函数,而PHP中对象销毁的方式有哪些:
析构函数:对象销毁时执行;注意在隐式销毁中是在是所有php代码执行完最后一行代码的时候才销毁,还有要注意在单入口文件下的MVC模式
对象的销毁:
- 显试销毁: 当对象没有被引用时就会被销毁,所以我们可以unset或为其赋值NULL;
- 隐试销毁:PHP是脚本语言,在代码执行完最后一行时,所有申请的内存都要释放掉.
Example1:
class Human {
public $name = '张三';
public $gender = null;
public function __destruct() {
echo '死了!<br />';
}
}
$a = new Human();
$b = $c = $d = $a;
unset($a);
echo '<hr />'; //析构函数究竟是触发了几次,是在线上触发,还是在线下触发?
答案:
$b = $c = $d = $a;默认引用传值,四个变量指向同一处内存,unset的时候对象还是被还是其它三个变量使用,所以对象并没有被销毁,所以析构函数是在线下触发的(代码执行完了,内存自动释放)
Example2:
class Human {
public $name = '张三';
public $gender = null;
public function __destruct() {
echo '死了!<br />';
}
}
$e = $f = $g = new Human();
unset($e);
unset($f);
unset($g);
echo '<hr />'; //同样的问题: 析构函数是在线上触发还是线下触发?
我相信通过Example1的讲解,应该很快知道答案是在线上触发;在代码运行完自动释放内存之前由于对象已经没有被任何变量引用所以就自动释放了内存....
最后:
其实这家面试是我第一家面试,各方面都还挺满意的,也谈妥了;但是我还是很想多面试几家,并不是为了去比价或者怎么的,很多时候我认为在面试中其实可以学到很多东西的。现在的人事小姐真的是巨能说话,架不住她的那种气场就答应早点上班了,真心想多面试几家~~唉!
从一次面试经历谈PHP的普通传值与引用传值以及unset的更多相关文章
- 2015腾讯暑期实习生 Web前端开发 面试经历
[2015腾讯暑期实习生 Web前端开发 面试经历] 好吧,首先声明,我被刷了,应该是跪在二面 微信查到的面试状态一直呈现复试中 .. 整整四天了.. 看来是没希望了 不过也是一次经历,记录一下还是可 ...
- Unity 工作经历+近期面试经历
由于团队解散,这最近都在找新工作机会--投简历找工作.已经面试三家了,都没拿到offer,挺失落的.把这种感受记录下来,以作后鉴. 这本质上是一篇面试经历的记录,并不是什么面试攻略,主要是给自己总结的 ...
- 学生党如何拿到阿里技术offer:《阿里面试经历-2014.4.18研发实习生面试经历(失败)》
我们分享的上一篇文章是一位学长在大三的时候面试阿里实习生成功的经历的分享,其实就像学长在上一篇文章最后说的那样“面试并没有想的那么难,运气也会占一部分.”,其实我个人觉得,对于我们而言,自己越努力就会 ...
- java开发实习生面试经历
这是我第一次写博客,以前都是查看别人的博客分享学习技术,转眼间我也成为其中一员.从一位初学者到现在的开发实习生,不断前进着,跟随时代的脚步在程序的海洋里漂泊,也意识到自己的各种不足,但我还年轻,头还 ...
- [原创]大连sap vt 实习生面试经历
从决定参加这次面试开始,求职生涯就算是开始了,虽然失败了,但也是亲身体会到了面试的感觉,这次经历也作为第一篇博客. 大连sap的职能是sap的全球技术支持中心和解决方案提供中心.VT项目提供的岗位是技 ...
- IBM 中国研究院面试经历
继上次面试MSRA失败后,严重刺激了我幼小的心灵.从此苦学算法准备面试很多其它其它的公司刷一刷Offer以解心 头之恨. 这个带来的IBM 中国研究院的面试经历. IBM的面试相比于MSRA.简直就是 ...
- Intel 的面试经历中国研究院
那么今天写Intel 的面试经历中国研究院.Intel我采访了面试题比较简单的一. 第一次是在大约下午五时三十, 我正在食堂和好几个基友吃20元巨资买的清蒸草鱼.正在吐沫星子四处飞溅的时候.一个010 ...
- 2019年京东Java研发岗社招面经(面试经历+真题总结+经验分享)!
本篇先以日历形式回顾秋招之路,方便各位参考某厂的处理进度:然后是总结归纳春秋招Java面试题库:最后做个总结还有展望,开始新的征程~ 面试经历京东面试真题面试经验分享1.面试经历 2018年的冬季特别 ...
- Android面试经历2018
本人14年7月份出来参加工作,至今工作将近4年的时间了,坐标是深圳.由于在目前的公司,感觉没什么成长,就想换一个公司.楼主已经在从实习到现在,已经换了三家公司了,所以这次出来的目标的100人以上,B轮 ...
随机推荐
- 我开发了一个产品--Markdown Notes
大家好,我开发了一个工具类软件产品--Markdown Notes,中文名是Markdown笔记.想写一篇有关它的文章,目的就是为了推广.推广.推广:) BTW:本文就是用这个工具所写的.
- 2013-07-23 IT 要闻速记快想
### ========================= ###苹果的新动向今天华尔街日报称,苹果正在测试13英寸的大号iPad,以及更大屏幕的iPhone.而早在五月份,韩国资讯网站 ET New ...
- 第29章 项目10:DIY街机游戏
1.问题 "Self-Defense Against Fresh Fruit":军士长指挥自己的士兵使用自我防御战术对抗以石榴.芒果.青梅和香蕉等新鲜水果入侵者.防御战术包括使用枪 ...
- Perl 关于 use strict 的用法
什么场合要用 use strict 当你的程序有一定的行数时,尤其是在一页放不下时,或者是你找不到发生错误的原因时. 为什么要用 use strict? 众多的原因之一是帮你寻找因为错误拼写造成的错误 ...
- Linux下C程序插入执行shell脚本
1.system(执行shell命令) 相关函数 fork,execve,waitpid,popen表头文件 #include<stdlib.h>定义函数 int system(const ...
- (转)Android Support Percent百分比布局
一.概述 周末游戏打得过猛,于是周天熬夜码代码,周一早上浑浑噩噩的发现 android-percent-support-lib-sample(https://github.com/JulienGeno ...
- oracle11g RAC添加节点
OS: [root@rac ~]# more /etc/oracle-releaseOracle Linux Server release 5.7 DB: SQL> SELECT * FROM ...
- linux 错误总结
帝国cms登录后台提示“登录成功”,接着又提示“您还未登录” 把帝国cms文件夹下的/e/data/adminlogin 目录权限不可写导致,请将此目录权限设置为777权限即可解决.就可以正常登录后台 ...
- 搭建Asp.Net MVC4
启动vs2012,开始创建一个新的web应用程序.使用菜单:“文件”>“新建项目” 请在左侧选择 Visual C#,然后选择ASP.NET MVC 4 Web 应用程序.命名您的工程为&quo ...
- java 并发编程
闭锁 一种可以延迟线程的进度直到其到达终止状态.可以用来确保某些活动直到其他活动都完成后才继续执行 例如: 确保某个计算在其需要的所有资源都被初始化了之后才继续执行. 确保某个服务在其他依赖的服务都启 ...