php专区

 首页 > php专区 > PHP进阶 > 方法&架构 > 从一次面试经历谈PHP的普通传值与引用传值以及unset

从一次面试经历谈PHP的普通传值与引用传值以及unset

分享到:
【字体:
导读:
         摘要:关于这个概念一般都会在PHP的第一堂课说变量的时候给介绍,并且我以前还给其他PHPer介绍这个概念。但是作为一个工作一段时间的PHPer的我,竟然在面试的时候一下子拿不定主意最后还答错了,很觉得丢脸...

从一次面试经历谈PHP的普通传值与引用传值以及unset

首先,要理解变量名存储在内存栈中,它是指向堆中具体内存的地址,通过变量名查找堆中的内存;
普通传值,传值以后,是不同的地址名称,指向不同的内存实体;
引用传值,传引用后,是不同的地址名称,但都指向同一个内存实体;改变其中一个,另外一个就也被改变;

以下我将通过三个列子来详细讲解这两个传值的区别:

Example1:

 //普通传值 $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:

 //函数中的普通传值 ↓↓ $param1 = 1; function add($param2){ $param2=3; } $param3=add($param1); //调用方法add,并将变量1传给变量2,此处是普通传值,所以变量1和变量2是两处内存,互不影响; echo '
$param1=='
.$param1.'
'
; //显示为$param1==1 echo '
$param2=='
.$param2.''; //显示为$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:

 //给数组里面的键值各增加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模式

对象的销毁

  1. 显试销毁: 当对象没有被引用时就会被销毁,所以我们可以unset或为其赋值NULL;
  2. 隐试销毁:PHP是脚本语言,在代码执行完最后一行时,所有申请的内存都要释放掉.

Example1:

class Human { public $name = '张三'; public $gender = null; public function __destruct() { echo '死了!
'
; } } $a = new Human(); $b = $c = $d = $a; unset($a); echo '
'
; //析构函数究竟是触发了几次,是在线上触发,还是在线下触发?

答案:

$b = $c = $d = $a;默认引用传值,四个变量指向同一处内存,unset的时候对象还是被还是其它三个变量使用,所以对象并没有被销毁,所以析构函数是在线下触发的(代码执行完了,内存自动释放)

Example2:

class Human { public $name = '张三'; public $gender = null; public function __destruct() { echo '死了!
'
; } } $e = $f = $g = new Human(); unset($e); unset($f); unset($g); echo '
'
; //同样的问题: 析构函数是在线上触发还是线下触发?

我相信通过Example1的讲解,应该很快知道答案是在线上触发;在代码运行完自动释放内存之前由于对象已经没有被任何变量引用所以就自动释放了内存....

从一次面试经历谈PHP的普通传值与引用传值以及unset
分享到:
PHP之父:PHP7 性能翻倍关键大揭秘
PHP之父:PHP7 性能翻倍关键大揭秘 原文出处: ithome 欢迎分享原创到伯乐头条 20岁老牌网页程序语言PHP,最快将在10月底释出PHP 7新版,这是十年来的首次大改版,最大特色是在性能上的大突破,能比前一版PHP 5快上一倍,PHP之父Rasmus Lerdorf表示,甚至能比HHVM虚拟机下的PHP程序性能更快。 HHVM 是脸书...
程序猿的架构设计之路(一):前言
程序猿的架构设计之路(一):前言  我学计算机学开发,目的很明确,就是奔着“架构”来的。当然,最初我不知道这个名词,我以为我就是去学“做网站”的。什么时候能够学会?最开始我以为三个月应该够了,然后延期到六个月,再延期到一年、两年……直到现在。在这个过程中, 我算是深刻的体会到“学无止境”,或者“学得...
  •         php迷,一个php技术的分享社区,专属您自己的技术摘抄本、收藏夹。
  • 在这里……