免費論壇 繁體 | 簡體
Sclub交友聊天~加入聊天室當版主
分享

【6】插播:深入理解PHP原理之变量赋值

本文来自:★flash之路-flash技术交流★ 转帖请注明出处! 作者:flashroad 您是第2482个浏览者

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
flashroad友情提示:
“点评”不是“回帖”!
您所在的用户组只能看到部分内容.
如查看全部内容, 请先登录或者注册.

友情提示:单击下列任意一个表情,即可瞬间自动回复本帖!

好贴......
郁闷......
开心......
擦汗......
鄙视......
狂怒
谢谢
爱你呦
拜托了
嗯嗯
OMG
求关注
伤心......
无奈.....
无奈.....
无奈.....
无奈.....
无奈.....
哈哈哈
NO
OK
what
我来了

最近访问本帖者列表:

flashroad
访问时间:2019-04-06 13:09

打赏

取消

感谢您的支持,我会继续努力的!

扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

Powered by 爱秀代码,分享从这里开始,精彩与您同在

点评
B Color Smilies

您还可以输入:个字符
X

X

在上一课《深入理解PHP原理之变量结构》中我已经介绍了PHP变量的内部结构,下面我将会对变量赋值过程中,PHP内部对数据处理的原理进行阐述,不过在讲述该原理前,需要先了解一下变量名和它的值是如何关联起来的,这个对变量赋值内部原理的理解非常重要,例如:
  1. <?php
  2.     $a = 1;
  3. ?>
复制


这个例子看起来非常简单,但是你知道“变量名a”和“数值1”是怎样关联起来的么?
在上节课一文中已经讲过,PHP中所有的值都是通过结构体zval存储的,大家如果对zval不太清楚,建议先看看上节课的内容,下面让我们先回顾一下zval
  1. struct _zval_struct {
  2.     zvalue_value value;       // 存储变量的值
  3.     zend_uint refcount__gc;   // 引用计数
  4.     zend_uchar type;          // 变量的类型
  5.     zend_uchar is_ref__gc;    // 是否引用
  6. } zval;
复制


有了数值zval和变量名a,下面就是如何将两者关联的问题了。
因为变量名a其实有一个指针ptr_a,每次初始化一个变量时,系统会先开辟一块内存,将变量的值保持在zval中,然后将变量a和对应的指针ptr_a保持在数值中,同时让ptr_a指向zval的首地址,如下图所示,是不是很简单呢,哈哈;P  
您所在的用户组只能看到部分内容.
如查看全部内容, 请先登录或者注册.
附件: 您需要登录才可以下载或查看附件。没有帐号?注册
点评
B Color Smilies

您还可以输入:个字符
X

X

TOP

知道变量名和它的值如何关联后,我们就可以开始深入了解变量赋值原理,为了方便大家理解,我将通过图文的方式来讲解。

对于变量赋值原理,《深入理解PHP内核》中将该部分内容分为5种情况,所以我也通过这5个部分进行讲解,不过对于里面有些代码的讲解,感觉有点问题,在此就不多提了哈,开始切入正题。

  情况1:赋值的左值is_ref=0,左值的refcount为1,左值==右值
  1. <?php
  2.    $a = 1;        
  3.    $a = $a;   
  4. ?>
复制
这种情况比较简单,refcount前后没有变化,不过在内核中,refcount其实进行了先减1,然后加1的操作。

========================================================
  情况2:赋值的左值is_ref=0,左值的refcount为1,右值is_ref=0
  1. <?php
  2.    $a = 1;        
  3.    $b = $a;   
  4. ?>
复制
按照常规思维,我们可能会给变量b重新申请一块内存,然后将a的值copy到自己的zval,如果真是这样的话,感觉非常low,当然PHP开发者也想到了这一点,对于这种情况,完全可以让a的指针ptr_a和b的指针ptr_b指向相同的zval,然后将引用计数refcount加1,不过这样会有个问题,如果将变量a销毁后,是不是zval空间会被释放,然后变量b的值也被销毁,或者还是通过其它的方式进行处理?(这个问题留给大家, 我就不解答了哈~~)


=====================================================
  情况3:赋值的左值is_ref=1,左值!=右值
  1. <?php
  2.    $a = 1;        
  3.    $b = &$a;   
  4.    $b = 2;
  5. ?>
复制
这里我们可以看到,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
  1. <?php
  2.    $a = 1;        
  3.    $b = &$a;
  4.    $c = $a;
  5. ?>
复制
前两步在之前已经说明,这里就不再赘述,在第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
  1. <?php
  2.    $a = 1;        
  3.    $b = 2;
  4.    $c = &$b;  
  5.    $a = $c;
  6. ?>
复制
这种情况比较复杂,前3步都比较好理解,但到第4步的时候,因为b和c属于引用关系,也可以理解为“等价”关系,然后a也有自己的zval,当第四步a=c时,不可能让c的ptr_c直接指向和a相同的zval,其实这里和“情况4”的处理方式几乎一样,唯一的区别是“情况4”是直接新开辟一块zval内存,而“情况5”并没有新开辟内存,而是将当前的zval中的值1修改为2。
您所在的用户组只能看到部分内容.
如查看全部内容, 请先登录或者注册.
附件: 您需要登录才可以下载或查看附件。没有帐号?注册

获得 小恶魔卡 一张

卡片说明:flashroad不小心破坏了公物,被警察叔叔扣掉5金钱

卡片效果:-5

点评
B Color Smilies

您还可以输入:个字符
X

X

TOP

后记:

这是我结合《深入理解PHP内核》一书和鸟哥的博客写的,将两种总结后,然后通过比较图像化的语言来描述,鸟哥的博客写的很生动的,但是有些情况没有覆盖,然后有些代码层次的东西没有讲出来,《深入理解PHP内核》书中,有些地方没有讲清楚,然后感觉有些代码写的有问题(不知道是真有问题,还是自己的理解错误,反正我是推敲了好长时间,后续我会查阅php源码),并且对于这5种情况,排序有点乱,所以我将它们重新归类了一下。至于这些图,是我在理解该原理的过程中,脑海中所浮现的,所以就将他们画了出来,希望对大家理解该部分内容会有所帮助。


参考: http://www.laruence.com/2008/09/19/520.html
您所在的用户组只能看到部分内容.
如查看全部内容, 请先登录或者注册.
点评
B Color Smilies

您还可以输入:个字符
X

X

TOP

 

B Color Image Link Quote Code Smilies
高级模式 | 发新话题

您需要登录后才可以回帖 登录|立即注册

快速
返回顶部
返回首页