PHP变量的销毁

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的垃圾回收机制会进行回收并释放那一块的内存。

zval更详细的了解

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(),如果对象有销毁的时候.则自动执行析构函数。

点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注