变量在内存中

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

example

<?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
?>
<?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 
?>

unset()

$a = 1;
$b = &$a;
unset($a);
echo $b; //??

但是要注意: unset并没有真正销毁变量的作用…仅仅是切断了变量与内存之间的关系,内存只要还被引用着就不会被释放; $b和$a同时指向1,切断其中$a的关系,$b还是指向1,所以上题不报错,照样输出1。

另外补充一点: 在PHP中对象的传值默认是引用传值

析构函数:对象销毁时执行;注意在隐式销毁中是在所有php代码执行完最后一行代码的时候才销毁,还有要注意在单入口文件下的MVC模式

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

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的时候对象还是被还是其它三个变量使用,所以对象并没有被销毁,所以析构函数是在线下触发的(代码执行完了,内存自动释放)

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 />'; //同样的问题: 析构函数是在线上触发还是线下触发?

线上,一次

Scroll to Top