徹底搞懂 PHP 變數結構體,多數文章觀點不準確

凌梅傲雪發表於2017-10-12

PHP5 中的 zval

// 1. zval
typedef struct _zval_struct {
    zvalue_value value;
    zend_uint refcount__gc;
    zend_uchar type;
    zend_uchar is_ref__gc;
} zval;

// 2. zvalue_value
typedef union _zvalue_value {
    long lval;     // 用於 bool 型別、整型和資源型別
    double dval;    // 用於浮點型別
    struct {     // 用於字串
        char *val;
        int len;
    } str;
    HashTable *ht;    // 用於陣列
    zend_object_value obj;  // 用於物件
    zend_ast *ast;    // 用於常量表示式(PHP5.6 才有)
} zvalue_value;

// 3. zend_object_value
typedef struct _zend_object_value {
    zend_object_handle handle;
    const zend_object_handlers *handlers;
} zend_object_value;

// 4. zend_object_handle
typedef unsigned int zend_object_handle;複製程式碼

多數文章,在提到PHP5 變數結構體的時候,都提到:sizeof(zval) == 24, sizeof(zvalue_value) == 16,實際上這個論述並不準確,在 CPU 為 64bit 時,這個結果是正確的。

但當 CPU 為32bit 時: sizeof(zval) == 16, sizeof(zvalue_value) == 8,主要因為 CPU 為 64bit 時,指標佔用8個位元組,而 32bit時,指標為4個位元組。

PHP 7 中的 zval

// 1. zval
struct _zval_struct {
    zend_value        value;            /* value */
    union {
        struct {
            ZEND_ENDIAN_LOHI_4(
                zend_uchar    type,            /* active type */
                zend_uchar    type_flags,
                zend_uchar    const_flags,
                zend_uchar    reserved)        /* call info for EX(This) */
        } v;
        uint32_t type_info;
    } u1;
    union {
        uint32_t     next;                 /* hash collision chain */
        uint32_t     cache_slot;           /* literal cache slot */
        uint32_t     lineno;               /* line number (for ast nodes) */
        uint32_t     num_args;             /* arguments number for EX(This) */
        uint32_t     fe_pos;               /* foreach position */
        uint32_t     fe_iter_idx;          /* foreach iterator index */
        uint32_t     access_flags;         /* class constant access flags */
        uint32_t     property_guard;       /* single property guard */
    } u2;
};

// 2. zend_value
typedef union _zend_value {
    zend_long         lval;                /* long value */
    double            dval;                /* double value */
    zend_refcounted  *counted;
    zend_string      *str;
    zend_array       *arr;
    zend_object      *obj;
    zend_resource    *res;
    zend_reference   *ref;
    zend_ast_ref     *ast;
    zval             *zv;
    void             *ptr;
    zend_class_entry *ce;
    zend_function    *func;
    struct {
        uint32_t w1;
        uint32_t w2;
    } ww;
} zend_value;複製程式碼

PHP 7的看似很多,但其實更簡單了,不論 CPU 是32bit 還是 64bit,sizeof(zval) 永遠都是等於 16。
主要看 zend_value 中的 ww,是兩個 uint32_t,這個永遠是 8 個位元組,所以 sizeof(zend_value) == 8,因此 sizeof(zval) == 16。

所以 PHP7 新特性提到的節省記憶體這點上,在 32bit 系統中,PHP5 => PHP7 並無變化。

順便說下 sizeof,不能當做函式,雖然寫法像函式,這個數值會在編譯期就確定好,非執行期。類似編譯預處理。

有關sizeof的詳情,可以看:
blog.csdn.net/yangtalent1…

這個CSDN 文章的排版雖然有些亂,但總結的都是精華,耐心看完,理解透徹後,就很容理解我上面的分析。

原文:www.yinqisen.cn/blog-781.ht…

相關文章