深入理解PHP原理之变量赋值
发布日期:2021-10-05 13:28:24 浏览次数:1 分类:技术文章

本文共 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:深入理解PHP原理之PHP与WEB服务器交互
下一篇:深入理解PHP原理之变量结构

发表评论

最新留言

很好
[***.229.124.182]2024年04月26日 08时54分15秒