首先,要理解变量名存储在内存栈中,它是指向堆中具体内存的地址,经过变量名查找堆中的内存;
普通传值,传值之后,是不一样的地址名称,指向不一样的内存实体;
引用传值,传引用后,是不一样的地址名称,但都指向同一个内存实体;改变其中一个,另一个就也被改变;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; } //调用方法add,并将变量1传给变量2,此处是普通传值,因此变量1和变量2是两处内存,互不影响; $param3=add($param1); echo '<br>$param1=='.$param1.'<br>'; //显示为$param1==1 //显示为$param2== 由于$param2是局部变量,函数运行完了之后就自动销毁,其不能影响全局 echo '<br>$param2=='.$param2.'<!-- <br> -->'; //函数中的引用传值 ↓↓ 注意,php不建议这样使用,而且php.in里面设置其会报错; $param1 = 1; function add($param2){ $param2=3; return $param2; } //调用方法add,并将变量1的引用传给变量2,此时两个地址指向同一内存,改变其中一个,另一个也要被改变; $param3=add(&$param1); echo $param1; //3,内存已在函数内部改变; echo $param3; //3 ?>
Example3:code
<?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; //??
可是要注意: unset并无真正销毁变量的做用...仅仅是切断了变量与内存之间的关系,内存只要还被引用着就不会被释放; $b和$a同时指向1,切断其中$a的关系,$b仍是指向1,因此上题不报错,照样输出1。内存
另外补充一点: 在PHP中对象的传值默认是引用传值io
再看一题:
在作这题以前咱们回顾一下什么是析构函数,而PHP中对象销毁的方式有哪些:function
析构函数:对象销毁时执行;注意在隐式销毁中是在是全部php代码执行完最后一行代码的时候才销毁,还有要注意在单入口文件下的MVC模式class
对象的销毁:
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的讲解,应该很快知道答案是在线上触发;在代码运行完自动释放内存以前因为对象已经没有被任何变量引用因此就自动释放了内存....