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内核中数组的实现。

  • 相关阅读:
    ubuntu 访问 共享 windows文件夹
    ubuntu下android环境的搭建
    smb使用 ------转载自http://blog.csdn.net/tlaff/article/details/5463068
    oracle jar
    悬浮按钮
    移动开发赚钱
    截取scrollview的滑动事件,传递给子控件
    put ListView in a ScrollView(bug fixed)
    35岁前务必成功的12级跳
    mysql分页原理和高效率的mysql分页查询语句
  • 原文地址:https://www.cnblogs.com/smilealgernon/p/3053107.html
Copyright © 2011-2022 走看看