zoukankan      html  css  js  c++  java
  • PHP源码阅读Part3变量

      注:这篇文章的内容出自ircmaxell的博客,这里只是翻译整理一下!

      这节我们将继续在上节的基础上,探讨PHP的内核实现,上节主要讲了如何在PHP源码中找到一个PHP函数的实现, 并以strpos函数为例,简要分析了它的实现过程。这节我们主要分析一下PHP中的变量,即源码中随处可见的zval类型。

    走进zval

      PHP是一种弱类型语言,不需要变量的类型声明,解释器会根据上下文环境,来决定当前变量是什么类型。PHP有Intger、String、Boolean、Float四种基本类型;Array、Object两种复合类型;还有Resource、NULL两种特殊类型。那么这些“PHP类型”是如何映射到“C类型”的呢。上节我们简单提到,PHP的整型对应着C的long类型。

      这些都跟zval结构体有关,在lxr.php.net中,搜索zval,会有很多结果,随便选一个进入,点击zval便可以跳转到zval的定义(在zend目录下的zend.h文件中)

    1 typedef struct _zval_struct zval;

       可见,zval是_zval_struct的别名,点击_zval_struct

    1 struct _zval_struct {
    2     /* Variable information */
    3     zvalue_value value;     /* value */
    4     zend_uint refcount__gc;
    5     zend_uchar type;    /* active type */
    6     zend_uchar is_ref__gc;
    7 };

      这个结构体看起来很简单,只有四个成员变量,但PHP中所有的变量都出自这里,这个结构体就是我们接下来的重点,我将会挨个分析这四个成员变量。

    Value

      这个变量是zvalue_value类型,用于存储PHP中变量的值,如:$var = 100;值100就存储在这里,点击跳到定义处。

     1 typedef union _zvalue_value {
     2     long lval;                  /* long value */
     3     double dval;                /* double value */
     4     struct {
     5         char *val;
     6         int len;
     7     } str;
     8     HashTable *ht;              /* hash table value */
     9     zend_object_value obj;
    10 } zvalue_value;

      注意到这是一个union类型,大家知道C语言中的union类型是一种很有趣的类型,它里面的成员变量都使用同一块内存,系统也只为这些变量分配一块内存,这块内存的大小取决于成员变量中占内存最大的变量,这就保证了这块内存可以容下任何一个成员变量。所以,union类型可以让一个变量根据访问的不同,被解释为不同的类型,比如:zvalue_value.lval = 123.321,内存中就会存一个long类型的变量。

      现在,我们仔细看看zvalue_value里的成员变量,一共有5个。

    • long lval                       表示PHP中的整型
    • double dval                  表示PHP中的浮点型
    • struct{...}                   表示PHP中的字符串
    • HashTable *ht          表示PHP中的数组
    • zend_object_value obj  表示PHP中的对象

       似乎还有Boolean、Resource、NULL三种没有提到,OK,已有的类型已经足够存储了,Boolean、Resource被存储为long,NULL不需要存储。

    TYPE

      OK,假设我们在PHP中定义了一个变量:$var = 'hello';对应到C代码,在给上面的value赋值的时候,我们怎么知道当前变量的类型的呢,这里的type成员变量就是实现这个功能的,如:tyle标识为String类型,就会通过value.str.char = 'hello'。

      zend目录下的zend.h文件定义了各种类型。

    1 #define IS_NULL     0
    2 #define IS_LONG     1
    3 #define IS_DOUBLE   2
    4 #define IS_BOOL     3
    5 #define IS_ARRAY    4
    6 #define IS_OBJECT   5
    7 #define IS_STRING   6
    8 #define IS_RESOURCE 7

    IS_REF

      这个变量是否被引用,比如:$foo = &$mm,那么$foo对应的is_ref会被赋值为1,否则为0。

    REFCOUNT

      引用次数,如果为1,表示只有一个变量指向这个zval示例,如果为2,表示有两个变量指向这个zval示例。is_ref和refcount结合底层优化和垃圾回收有重要的作用,想更深入的理解,可以参考这里

      至此,zval的成员变量介绍完毕。

    如何操作zval

      zval应该是内核中操作最频繁的结构体了,对zval的增删改查操作,是通过定义了几个宏来实现的,这样做很方便,我们在上一节中也遇到过这些宏指令。

    在zend目录下的zend_operators.h文件中,我们可以看到:

    1 #define Z_LVAL(zval)            (zval).value.lval
    2 #define Z_BVAL(zval)            ((zend_bool)(zval).value.lval)
    3 #define Z_DVAL(zval)            (zval).value.dval
    4 #define Z_STRVAL(zval)          (zval).value.str.val
    5 #define Z_STRLEN(zval)          (zval).value.str.len
    6 #define Z_ARRVAL(zval)          (zval).value.ht
    7 #define Z_OBJVAL(zval)          (zval).value.obj
    ...

      这些宏指令很精简 ,这里就不再介绍了

    类型转化

      PHP会自动为我们做类型转化的,因此你可以将一个字符串当作整型使用,在内核中是通过convert_to_type函数来完成的,它将会zval的type改为整型。

    Zend_Parse_Parameters

      这个函数我们上节中提到过,如果你想了解内核中类型的转换过程,这个函数的源码肯定可以让你大饱眼福,详情可以在这里看到。

    下一篇博文

      下一节,我们将会探讨PHP内核中数组的实现。

  • 相关阅读:
    第36课 经典问题解析三
    第35课 函数对象分析
    67. Add Binary
    66. Plus One
    58. Length of Last Word
    53. Maximum Subarray
    38. Count and Say
    35. Search Insert Position
    28. Implement strStr()
    27. Remove Element
  • 原文地址:https://www.cnblogs.com/smilealgernon/p/3053107.html
Copyright © 2011-2022 走看看