PHP的常量无法销毁,只能等程序结束,而变量可以手动销毁。PHP的变量或对象的销毁可以分成显式销毁和隐式销毁。
1、显式销毁,当对象没有被引用时就会被销毁,所以我们可以unset或为其赋值NULL;
2、隐式销毁,PHP是脚本语言,在代码执行完最后一行时,所有申请的内存都要释放掉.
因此销毁变量有以下三种方法:
1、unset(),2、$varname=null,3、析构函数__destruct()。
变量的容器-Zval
在语言的运用中我们常常需要跟变量打交道,不管这个变量是数字、数组、字符串、对象还是其他,因而可以说变量是构成语言的不可或缺的基础。而在PHP中变量的容器-Zval也至关重要。
Zval是PHP中最重要的数据结构之一(另一个比较重要的数据结构是hash table),它包含了PHP中的变量值和类型的相关信息。
在zval中,对PHP的变量类型分为了两种实现形式:对于常规类型,数据的值是直接存储在zval中的;对于对象、数组这类复杂的类型,数据的值是剥离zval,存储在内存的其他地方的,而zval中只存储了那块存储数据的内存地址。
符号表是PHP程序中变量名称和zval值对应关系的存储场所,在PHP底层实现中,是使用HashTable实现的。
在我们unset变量时,实际上PHP只是从符号表里标记清除了这个变量的zval。但由于HashTable是直接存储zval而非引用存储的,所以符号表中所占用的zval内存实际上没有真正释放。当然,在某些对符号表的操作中,可能会触发符号表的自我伸缩,这时候才会真正的对内存进行申请和释放。
另外一方面,如果我们unset的是PHP的复杂类型,除了符号表中的zval外,数据的内容实际上存储在另外一块内存中。对于这种引用类型,PHP都会带有一个refcount引用计数,当zval被清除或者其他操作减少了对象的引用时,变量的引用计数会减一。而如果引用计数为零,则表示变量已经不在PHP程序中被使用了。而对于这类变量,PHP的垃圾回收机制会进行回收并释放那一块的内存。
unset()销毁变量
在PHP中,变量名是存储在内存栈中,它是指向堆中具体内存的地址,通过变量名查找堆中的内存
<?php
$a = 1;
$b = &$a;
unset($a);
var_dump($a);
var_dump($b);
?>
结果:
NULL
int(1)
变量a被销毁,可是变量b的引用任然指向变量a的内存,所以unset()并没有真正销毁变量中内存值,仅仅是切断了变量与内存之间的关系,并将变量名也给干掉了,但内存只要还被引用着就不会被释放(在PHP中对象的传值默认是引用传值)
$varname=null销毁变量
$varname=null,变量名依然存在,但是内存值却被干掉了。那么在引用传值的情况下又是如何呢?
<?php
$a = 1;
$b = &$a;
$a=null;
var_dump($a);
var_dump($b);
?>
结果:
NULL
NULL
所以,$varname=null,虽然变量名和内存指向都还存在,但是内存中的值却是完全删除掉了。
__destruct()销毁
<?php
class Human{
public $name = '开始';
public function __destruct(){
echo '结束';
}}
$a = new Human;
echo $a->name;
unset($a); //销毁函数
$a = new Human;
echo '***********************';
?>
结果
开始结束***********************结束
以上结果说明代码并没有执行完最后一行的时候启动,而是当对象销毁的时候自动执行。之所以在human()函数也有unset()的情况下,析构函数__destruct()还是在最后执行,那是因为引用传值,对象的内存并没有取消,对象并没有完全销毁导致。所以结论是:如果没有人为销毁的话.则在代码执行结束之后,系统自动释放内存时执行析构函数__destruct(),如果对象有销毁的时候.则自动执行析构函数。