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

PHP底层原理之变量(二)

时间:2023-03-29 18:52:53 PHP

上周我们介绍了PHP变量从生成->常量赋值->销毁变量的完整生命周期(一)),但是我们留下了一个想法,我没有知道你有没有答案,底层是如何实现变量之间的赋值的?变量之间赋值PHP变量的zval结构我们已经介绍过很多次了,这里就不再介绍了。不过zval结构体中的refcount__gc和is_ref__gc字段我们并没有详细介绍,而这两个字段其实和变量之间的赋值原理密切相关。那么,这次我们先从几个例子开始,了解一下这两个字段的变化以及由此产生的copy-on-write原理的知识Example:$a="徐峥的技术成长之路";$b=$a;xdebug_debug_zval("a","b");结果:a:(refcount=2,is_ref=0)='徐峥的技术成长之路'b:(refcount=2,is_ref=0)=《徐峥科技成长之路》看到这里,大家可能会一头雾水。不是变量赋值吗?是否应该复制该值?怎么两个变量的引用计数不是1,而是2?那是因为,PHP在设计的时候为了节省内存,在变量之间赋值的时候,两个相同值的变量会共享一块内存,也就是全局符号中会指向变量b的变量指针table变量a指向同一个zval结构,只有当变量的zval结构发生变化时,才会发生变量容器copy的内存变化,也称为copy-on-write原则。什么时候会出现写时复制原则?copy-on-write原理的触发时机:当php修改一个变量时,如果发现该变量的refcount>1,就会执行该变量容器的内存拷贝例子:$a="徐峥科技成长小路”;$b=$a;//此时变量a和变量b指向同一个变量容器,即refcount>1$b="徐峥技术成长之路1"//触发copy-on-write机制xdebug_debug_zval("a","b");结果:a:(refcount=1,is_ref=0)='徐峥的技术成长路径'b:(refcount=1,is_ref=0)='徐峥的技术成长路径1'写We的时候改弄清楚了principal变量之间的赋值,那么变量和引用之间的赋值呢?下面用一个例子来说明例子:$a="徐峥的技术成长之路";$b=&$a;xdebug_debug_zval("a","b");结果:a:(refcount=2,is_ref=1)='徐峥的技术成长之路'b:(refcount=2,is_ref=1)='徐峥的科技成长之路'这时候我们发现变量a和b的refcount还是2,但是is_ref变成了1,那是因为当变量a的引用赋值给变量b时,原来的变量容器被修改了,is_ref变成了1,refcount+1,如果在引用赋值的基础上生成的变量变了?例如:$a="徐峥的技术成长之路";$b=&$a;$b="徐峥的技术成长之路1"xdebug_debug_zval("a","b");结果:a:(refcount=2,is_ref=1)='徐峥的技术成长路径1'b:(refcount=2,is_ref=1)='徐峥的技术成长路径1'是不是觉得很神奇?变量b和变量a的值一起变了~其实这是因为change-on-write原理触发了change-on-write原理的时机:给is_ref为1的变量container赋值前,先检查变量container的is_ref是否等于1,如果为1则不进行copy-on-write,但会修改内容在原有可变容器的基础上;而如果is_ref为1时,变量容器赋值给其他变量时,会立即触发copy-on-write。那么,如果将刚才给出的几个例子合并在一起呢?最后的结果是什么?例:$a="徐峥的技术成长之路";$b=$a;$c=&$a;xdebug_debug_zval("a","b","c");结果:a:(refcount=2,is_ref=1)='徐峥的技术成长之路'b:(refcount=1,is_ref=0)='徐峥的技术成长之路'c:(refcount=2,is_ref=1)='徐峥的科技成长之路'整体执行流程是这样的,当执行到第二行时,refcount变量容器的个数会变成2个,变量a和变量b共享同一个变量容器;当执行到第三行时,因为变量a的引用赋值给了变量c,但是变量b和变量a已经共享了同一个变量容器。如果此时要改变变量容器,因为refcount>2,会发生copy-on-write,将变量a从变量b中分离出来,然后将变量a引用赋值给变量c,就会被修改在原来的基础上,is_ref变成了1,refcount变成了2想一想,下面这个例子最后的结果是什么呢?欢迎大家在下方留言或者私信我~比如:$a="徐峥的技术成长之路";$b=$a;$c=&$a;$d=$a;$e="徐峥的技术成长之路1"$a=$e;xdebug_debug_zval("a","b","c","d",“e”);如果喜欢我的文章,请点赞支持,也欢迎关注我的专栏,每周都会有原创深度文章哦~