本文共 2167 字,大约阅读时间需要 7 分钟。
在前面的文章《》中我已经介绍了PHP变量的内部结构,下面我将会对变量赋值过程中,PHP内部对数据处理的原理进行阐述,不过在讲述该原理前,需要先了解一下变量名和它的值是如何关联起来的,这个对变量赋值内部原理的理解非常重要,例如:
这个例子看起来非常简单,但是你知道“变量名a”和“数值1”是怎样关联起来的么?在《》一文中已经讲过,PHP中所有的值都是通过结构体zval存储的,大家如果对zval不太清楚,建议先看看这篇博文,下面让我们先回顾一下zval:
struct _zval_struct { zvalue_value value; // 存储变量的值 zend_uint refcount__gc; // 引用计数 zend_uchar type; // 变量的类型 zend_uchar is_ref__gc; // 是否引用} zval;
有了数值zval和变量名a,下面就是如何将两者关联的问题了。因为变量名a其实有一个指针ptr_a,每次初始化一个变量时,系统会先开辟一块内存,将变量的值保持在zval中,然后将变量a和对应的指针ptr_a保持在数值中,同时让ptr_a指向zval的首地址,如下图所示,是不是很简单呢,哈哈:)
知道变量名和它的值如何关联后,我们就可以开始深入了解变量赋值原理,为了方便大家理解,我将通过图文的方式来讲解。对于变量赋值原理,《深入理解PHP内核》中将该部分内容分为5种情况,所以我也通过这5个部分进行讲解,不过对于里面有些代码的讲解,感觉有点问题,在此就不多提了哈,开始切入正题。 情况1:赋值的左值is_ref=0,左值的refcount为1,左值==右值这种情况比较简单,refcount前后没有变化,不过在内核中,refcount其实进行了先减1,然后加1的操作。
情况2:赋值的左值is_ref=0,左值的refcount为1,右值is_ref=0按照常规思维,我们可能会给变量b重新申请一块内存,然后将a的值copy到自己的zval,如果真是这样的话,感觉非常low,当然PHP开发者也想到了这一点,对于这种情况,完全可以让a的指针ptr_a和b的指针ptr_b指向相同的zval,然后将引用计数refcount加1,不过这样会有个问题,如果将变量a销毁后,是不是zval空间会被释放,然后变量b的值也被销毁,或者还是通过其它的方式进行处理?(这个问题留给大家, 我就不解答了哈~~)
情况3:赋值的左值is_ref=1,左值!=右值这里我们可以看到,a是通过引用的方式给b赋值,当给b赋值为2时,a的值其实也变为2,那么php内核是怎么处理的呢?方法其实同“情况2”一样,唯一的区别就是将是否引用is_ref赋值为1,至于这个is_rel有啥作用,后面的情况会用到。然后,当给变量b赋值为2时,php内核会进行copy on write(写时复制)操作,即将zval中的值修改为2。(这么理解比较简单,其实源代码的处理过程要稍微复杂些,php内核首先会将整形2的zval copy过来,然后修改refcount和is_ref变量值,最后释放整形2的zval内存)
情况4:赋值的左值is_ref=0,左值的refcount为1,右值is_ref=1前两步在之前已经说明,这里就不再赘述,在第3步中,将变量a赋值给变量c,但是a是个引用,大家可以和“情况2”对比一下,这两种情况比较像,如果按照“情况2”的处理方式,让ptr_c指向a的zval,那么这样和c=&a又有什么区别呢?所以我们只能采取变量分离的策略,即给c单独开辟一块zval内存,然后将a的zval copy过来,这样c和a也就没有任何关系,所以c的refcount=1,该过程我们也称为change on write(写时改变)。
情况5:赋值的左值is_ref=0,左值refcount!=1,右值is_ref=1,右值refcount>0这种情况比较复杂,前3步都比较好理解,但到第4步的时候,因为b和c属于引用关系,也可以理解为“等价”关系,然后a也有自己的zval,当第四步a=c时,不可能让c的ptr_c直接指向和a相同的zval,其实这里和“情况4”的处理方式几乎一样,唯一的区别是“情况4”是直接新开辟一块zval内存,而“情况5”并没有新开辟内存,而是将当前的zval中的值1修改为2。
后记:这是我结合《深入理解PHP内核》一书和鸟哥的博客写的,将两种总结后,然后通过比较图像化的语言来描述,鸟哥的博客写的很生动的,但是有些情况没有覆盖,然后有些代码层次的东西没有讲出来,《深入理解PHP内核》书中,有些地方没有讲清楚,然后感觉有些代码写的有问题(不知道是真有问题,还是自己的理解错误,反正我是推敲了好长时间,后续我会查阅php源码),并且对于这5种情况,排序有点乱,所以我将它们重新归类了一下。至于这些图,是我在理解该原理的过程中,脑海中所浮现的,所以就将他们画了出来,希望对大家理解该部分内容会有所帮助。参考:
转载地址:https://blog.csdn.net/lml200701158/article/details/52235996 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!