深入PHP使用技巧之变量.doc_第1页
深入PHP使用技巧之变量.doc_第2页
深入PHP使用技巧之变量.doc_第3页
深入PHP使用技巧之变量.doc_第4页
免费预览已结束,剩余1页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

众所周知,PHP与其他脚本语言一样,属于弱变量类型的语言。同时PHP本身也是通过C语言来实现。本文 主要介绍PHP内部是如何实现弱变量类型的,并且据此分析在PHP开发中需要注意的一些使用技术。其中会重点分析PHP中的copy on write机制和引用相关方面的话题。 本章节属于深入PHP使用技巧的第一部分。如何实现弱变量在了解PHP实现弱变量类型之前,可以先思考下:如何通过C/C+来实现弱变量类型的效果呢?这个问题我在BIT培训课上基本上有两种答案:方法1:采用C+的继承机制。首先定义一个基础类型Class Var然后基于Var,派生出不同的子类型IntVar/FloatVar/StringVar等等。方法2:基于C语言的 Struct。其中一个字段用于标识类型,另外一个字段用于存储数据,由于数据要是各种类型,所以通常需要采用指针比如:struct var Int type;Void *data;两种思路本身并没有太大区别,也都基本上能够满足需求。在PHP中采用了第二种思路,并且做了比较多的优化。在PHP中,所有的变量都会对应同一种类型zval,其中zval也就是struct _zval_struct,具体定义如下:typedef union _zvalue_value long lval; /* long value */double dval; /* double value */struct char *val;int len; str;HashTable *ht; /* hash table value */zend_object_value obj; zvalue_value;struct _zval_struct /* Variable information */zvalue_value value; /* value */zend_uint refcount;zend_uchar type; /* active type */zend_uchar is_ref;从zval可以看出,PHP在细节方面的确做了不少优化的功夫。1.zend_uchar type。采用uchar节省内存。2.zvalue_value value; 采用union来替换void *,这样同样能节省空间,并且比void *更能表义清晰。3.在字符串类型中,默认保留了字符串的长度。这样很容易做到字符串的二进制安全,并且在计算字符串长度的时候不需要进行扫描。观察PHP弱变量的实现,也会有以下疑惑:1.为什么会没有int类型呢?其实在PHP中是有的,只是说默认int数据就保存在long中。2.资源类型咋表现的呢?资源在PHP内部其实就是一数字。详细后续会介绍。3.refcount和is_ref是干嘛的呢?呵呵,这就是第二部分要介绍的了。Reference counting & Copy-on-WritePHP和其他语言类似,在其语法中有两种赋值方式:引用赋值和非引用赋值(普通的=赋值)。引用赋值和非引用赋值在PHP内部是如何实现的呢?一种通常的认识是:“引用赋值就是两个变量对应同一个Zval,非引用赋值则是直接产生一个新的zval,同时把对应的值直接copy过来。”也就是该代码的内存结构如下: (该图是大多数人认为的PHP内存结构,是错误的)这样的确能够满足大部分情况下的需求,但显然不是最佳的解决方案,尤其是在内存管理上,比如说以下代码就会显得非常的低效。因为每次函数调用会进行一次内存dump,而大内存的内存dump是非常耗CPU的。在C语言中,一种解决方案是采用指针,所有函数调用尽量传递指 针。的确很灵活高效,但也很难维护指针可以说是C语言程序员心头的痛(当然也是福_)。还有一种更高级更有效的方法是采用引用计数 (Reference counting)。在PHP中,也可以采用引用来解决这样的问题,但你见过采用在PHP中大量使用引用的吗?显然很少。在PHP内核中,Zval的实现正是采用了引用计数的概念,说起引用计数就不得不谈到copy-on-write 机制。这样前面谈到的refcount和is_ref就有作用了。refcount:引用次数。在zval初始创建的时候就为1。每增加一个引用,则refcount +。is_ref:用于表示一个zval是否是引用状态。zval初始化的情况下会是0,表示不是引用。在Zend/Zend.h内部有一些关于ZVAL的宏定义,里面比较清晰的解析了引用计数的一些规则,其中重点关注以下几个宏定义#define INIT_PZVAL(z) (z)-refcount = 1; (z)-is_ref = 0;#define SEPARATE_ZVAL_IF_NOT_REF(ppzv) /非引用下的变量分离if (!PZVAL_IS_REF(*ppzv) SEPARATE_ZVAL(ppzv); #define SEPARATE_ZVAL_TO_MAKE_IS_REF(ppzv) /非引用下的变量分离,并且设置引用if (!PZVAL_IS_REF(*ppzv) SEPARATE_ZVAL(ppzv); (*(ppzv)-is_ref = 1; #define SEPARATE_ARG_IF_REF(varptr) /引用下的变量分离if (PZVAL_IS_REF(varptr) zval *original_var = varptr; ALLOC_ZVAL(varptr); varptr-value = original_var-value; varptr-type = original_var-type; varptr-is_ref = 0; varptr-refcount = 1; zval_copy_ctor(varptr); else varptr-refcount+; 这里面谈到两个重要的概念:1、非引用下的变量分离。非引用下的变量分离,是指在一堆非引用变量中插入引用的情况下,在PHP内部进行的一种内存操作。以下面的列子来看:$a = 1;$b = $a;$c = &$b;在前两句执行之后,内存结构如下图 在第三句 $c = &$b;语句中则会执行“非引用下的变量分离。”,具体步骤是:将b分离出来,同时把a对应的zval的refcount-1。copy 出一个新的zval,并把zval的is_ref设置成1.把C指向这个新的zval,同时refcount +最终效果如下图: 2、引用下的变量分离。引用下的变量分离,是指在一堆引用变量中进行一个非引用赋值操作,这个时候会直接执行copy内存的操作。以下面的例子来说$a = 1;$b = &$a;$c = $b;在执行完前两行后,PHP中内存结构如下: 在第三句,则会执行“引用下的变量分离”也就是真正的copy,最终内存结构如下图 据此,基本上对PHP变量内部的一些原理比较清楚了,但还有一些需要注意点的:1、PHP变量的引用计数特性,对于数组同样也存在。但注意,对于key则不生效。(具体在后面章节会分析到。)2、PHP变量中的对象比较特殊,在PHP5之后,默认都是采用引用赋值的方式。具体实现可以参考Zend_objects.*系列代码。3、对于分析PHP内部变量,推荐采用xdebug_debug_zval,而不要采用内置的debug_zval_dump。因为PHP

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论