当前位置: 首页 > 后端技术 > PHP

PHP赋值在内部是如何工作的?

时间:2023-03-29 13:42:38 PHP

在PHP中,当一个变量被赋值时,其内部经过了怎样的逻辑判断?PHP通过内核中的zval结构来存储变量。它的定义在Zend/zend.h文件中。使用xdebug的xdebug_debug_zval函数可以打印出变量的refcount和is_ref的值。如何在内核中执行以上内容?可以看出,在给变量赋值的时候,两个变量实际上指向了同一个地址空间。那么问题来了,如果指向同一个地址空间,那么不修改a,b也会随之改变。这就涉及到了php的copy-on-write机制。对于上面的代码,如果下面这行$b='123',判断过程如下:如果这个变量的zval部分的refcount小于2,说明没有其他变量在使用,那么修改这个值直接;否则,复制zval的值,减少原zval的refcount值,初始化新zval的refcount,修改新复制的zval简单变量。普通赋值输出如下:$a赋值,开辟104byte空间,变量arefcount=1,is_ref=0$b赋值,开辟48byte空间,变量arefcount=2,is_ref=1。48byte被符号表占用,a和b执行同一地址空间$c赋值,开辟104byte空间。由于a和b是引用,当c赋值时,会开辟一个新的空间,复制azval的内容,并初始化refcount和is_ref,所以a的refcount不会改变,c的refcount=1会正常赋值然后引用输出内容如下:$a赋值开辟104byte空间,变量arefcount=1,is_ref=0$b赋值开辟48byte空间,变量arefcount=2,is_ref=1.48byte被符号表占用,a和b指向同一个地址空间赋值$c开辟104byte空间。由于a和c是引用,需要和b隔离,所以会赋值原来的zval,初始化zval,a和c指向新复制的zval,输出原来的zvalrefcount-1数组为如下:上面这段测试代码非常相似,唯一不同的是arr[1]是否为引用赋值。在arr[1]非引用赋值的情况下,arr[0]的refcount=赋值次数+1,执行两次unset后,arr和arr[0]的refcount与最初时相同定义。在arr[1]引用赋值的情况下,arr[0]的refcount=非引用赋值的次数+1,执行两次unset后,arr和arr[0]的refcount不能返回到赋值处的值定义时间。主要原因是arr[1]引用赋值构成递归操作。但是,如果,对于这个refcount,我真的是看不懂。当没有arr[2]赋值时,执行unset,arrrefcount可以返回1。从下图可以更清楚的看出,当内部递归引用发生时,refcount应该=1,但是并没有设置为1.在这种情况下,会发生内存泄漏。上面代码循环执行100次,内存从一开始的121096增加到169224,内存占用增加了5k。以上对象输出的内容是xdebug给出的_ref=0。refcount与普通变量相同。但是班级分配是参考分配。以上内容的输出:在这里,由于类的赋值是引用赋值,索引也构成了递归操作,同样会像数组一样造成内存泄漏。对于后面的代码,第一段代码前后的内存差为1408字节。第二个代码是208字节。