PHP源码分析-变量

本文第一部分和第二均翻译自Nikita Popov(nikic,PHP
官方开发组成员,柏林科技大学的学生)
的博客。为了更符合汉语的阅读习惯,文中并不会逐字逐句的翻译。

  1. 变量的三要素
    变量名称,变量类型,变量值

要理解本文,你应该对 PHP5 中变量的实现有了一些了解,本文重点在于解释
PHP7 中 zval 的变化。

那么在PHP用户态下变量类型都有哪些,如下:

第一部分讲了 PHP5
和 PHP7 中关于变量最基础的实现和变化。这里再重复一下,主要的变化就是
zval
不再单独分配内存,不自己存储引用计数。整型浮点型等简单类型直接存储在
zval 中。复杂类型则通过指针指向一个独立的结构体。

// Zend/zend.h
#define IS_NULL     0
 #define IS_LONG     1
 #define IS_DOUBLE   2
 #define IS_BOOL     3
 #define IS_ARRAY    4
 #define IS_OBJECT   5
 #define IS_STRING   6
 #define IS_RESOURCE 7
 #define IS_CONSTANT 8
 #define IS_CONSTANT_AST 9
 #define IS_CALLABLE 10

复杂的 zval 数据值有一个共同的头,其结构由 zend_refcounted 定义:

  1. 变量值和变量类型的存储
    变量的类型和值被存储在结构体zval中,如下:

    / Zend/zend_types.h
    typedef struct _zval_struct zval;

    // Zend/zend.h
    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;
      zend_ast *ast;
    

    } zvalue_value;

    struct _zval_struct {

      /* Variable information */
      zvalue_value value;     /* value */
      zend_uint refcount__gc;
      zend_uchar type;    /* active type */
      zend_uchar is_ref__gc;
    

    };

struct _zend_refcounted {
    uint32_t refcount;
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,
                zend_uchar    flags,
                uint16_t      gc_info)
        } v;
        uint32_t type_info;
    } u;
};

先看结构体_zval_struct,它的成员中value存储变量的值,type存储变量的类型,refcount__gc和is_ref__gc是变量引用相关的标记,先忽略;
而具体存储变量值的结构体_zvalue_value如何存储一个变量的值呢?根据变量的类型进行不同方式的存储,如下:
a. 变量类型为boolean(ZVAL_BOOL), integer(ZVAL_LONG),
resource(ZVAL_RESOURCE)
zval中的type存储变量类型(IS_BOOL, IS_LONG,
IS_RESOURCE),zvalue_value中的lval存储变量值
b. 变量类型为float(ZVAL_DOUBLE)
zval中的type存储变量类型(IS_DOUBLE),zvalue_value中的dval存储变量值
c. 变量类型为null(ZVAL_NULL)
zval中的type存储变量类型(IS_NULL),不需要存储值
d. 变量类型为字符串
zval中的type存储变量类型(IS_STRING),zvalue_value中的结构体str存储字符串值和字符串长度
e. 变量类型为数组
zval中的type存储变量类型(IS_ARRAY),zvalue_value中的*ht将指向一个哈希表,而这个哈希表里则存储数组的值
f. 变量类型为对象
zval中的type存储变量类型(IS_OBJECT),zvalue_澳门新葡亰网址,value中的obj用于存储其值

这个头存储有 refcount(引用计数),值的类型 type
和循环回收的相关信息 gc_info 以及类型标志位 flags

以上对于变量类型为数组时,数组值是使用内核态的哈希表存储的,那么PHP内核态的哈希表到底是个什么东东?

接下来会对每种复杂类型的实现单独进行分析并和 PHP5
的实现进行比较。引用虽然也属于复杂类型,但是上一部分已经介绍过了,这里就不再赘述。另外这里也不会讲到资源类型(因为作者觉得资源类型没什么好讲的)。

  1. PHP内核态的哈希表

    / Zend/zend_hash.h
    typedef struct bucket {

      ulong h;                        /* Used for numeric indexing */
      uint nKeyLength;
      void *pData;
      void *pDataPtr;
      struct bucket *pListNext;
      struct bucket *pListLast;
      struct bucket *pNext;
      struct bucket *pLast;
      const char *arKey;
    

    } Bucket;

    typedef struct _hashtable {

      uint nTableSize;
      uint nTableMask;
      uint nNumOfElements;
      ulong nNextFreeElement;
      Bucket *pInternalPointer;   /* Used for element traversal */
      Bucket *pListHead;
      Bucket *pListTail;
      Bucket **arBuckets;
      dtor_func_t pDestructor;
      zend_bool persistent;
      unsigned char nApplyCount;
      zend_bool bApplyProtection;
    

    #if ZEND_DEBUG

      int inconsistent;
    

    #endif
    } HashTable;

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章

网站地图xml地图