变量是什么:
一个容器,用来装一些数据信息。相对于物理内存而言,我们的变量就是一些与其物理区域建立映射的代号。
任何语言,都需要变量来对数据进行存储。在强类型语言当中,变量往往都会有特定的类型限制(字符串、数组、对象...)。而对于php这类弱类型语言,变量可以在不同的数据类型之间进行转换,同一个变量,可能上一时刻还是一个字符串,下一个时刻就变成了一个数组。
我们知道在内存中,会分配一部分空间专门存放变量的地址,分配另一部分空间存放变量的值。在php内核中,主要是采用了COW(Copy-on-Write--写时复制机制),也就是说在写入时,才真正复制一份内存进行修改。这样通过变量赋值时,不会申请新的内存来存值,而是与原变量的值共用一个内存,从而减少对内存的占用。
下面通过几个例子来简单理解下这个概念。
- eg1:
$a = 1;
$b = 2;
- eg2:
$a = 1;
$b = $a;
- eg3:
$a = 1;
$b = &$a;
好了,有了上面的基本概念,接下来和大家一起来探讨一下,关于php中用来存储变量的容器----”zval”。
在”zval”当中,这个容器的内部,既有变量对应的值,也有变量对应的数据类型。同时,变量容器中还包含了区分该变量是否为引用变量(is_ref,默认值为0,表示为非引用变量),以及对应值的引用计数(refcount,用来表示指向这个变量容器的变量个数)。
- eg4:
$a = 1;
$b = 2;
$c =”cool”;
- eg5:
$a = 1;
$b = $a;
$c = 1;
- eg6:
$a = 1;
$b = &$a;
$c = $a;
在eg5当中,我们可以看到:
1.当php在执行 $b=$a时,Zend不会再创建一个zval容器,而是将$a对应的zval容器中的 refcount的值变加1;这样可以节省内存空间(当变量为一个很大的对象或数组时;或者某个变量被赋值给多个其他变量的情况);
2.我们对 $c 进行赋值,虽然与$a值相同都为1,但是同样也会为其分为一个新的zval容器,因为这是直接写入的一个值,而不是通过变量的赋值传递。
在eg6当中,因为$b是针对$a的引用赋值,在zval容器中,故is_ref引用变量标识变为1。
知道了php变量的存储方式,可以帮我们更清晰的理解关于php的变量内存分配模式(引用赋值、传递赋值)、内存回收机制(unset)的基础原理。