PHP是怎么存儲(chǔ)變量的

本篇內(nèi)容主要講解“PHP是怎么存儲(chǔ)變量的”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“PHP是怎么存儲(chǔ)變量的”吧!

創(chuàng)新互聯(lián)主營(yíng)灣里網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都app軟件開(kāi)發(fā),灣里h5重慶小程序開(kāi)發(fā)公司搭建,灣里網(wǎng)站營(yíng)銷推廣歡迎灣里等地區(qū)企業(yè)咨詢

PHP 源碼中的 zval

在 PHP 中定義一個(gè)變量是不需要聲明類型的,一開(kāi)始給變量 $a 賦予一個(gè)整型值,后面又可以輕而易舉地將其改變?yōu)槠渌愋汀D窃?PHP 的源碼中是如何來(lái)存儲(chǔ)這個(gè)變量 $a 的呢?帶著這個(gè)疑問(wèn)我們一起去看一看 PHP 的源碼。

PHP 的源碼是由 C 編寫的,在 PHP 的源碼中使用了一個(gè) zval 的結(jié)構(gòu)體來(lái)存儲(chǔ)在 PHP 代碼中創(chuàng)建的變量。我們把 zval 結(jié)構(gòu)體的定義拿出來(lái)簡(jiǎn)單分析一下。

這是 PHP 在 Github 上的官方倉(cāng)庫(kù):github.com/php/php-src,本文使用的分支是 PHP-7.4.29。

zval 結(jié)構(gòu)體

在 PHP 的源碼中找到這個(gè)文件:php-src/Zend/zend_types.h,可以看到其中 zval 結(jié)構(gòu)體的定義如下,左側(cè)是源碼。源碼中使用了 PHP 自己定義的類型 zend_uchar 、uint16_t 、uint32_t 等,這些類型會(huì)針對(duì)不同平臺(tái)和編譯器會(huì)轉(zhuǎn)為該平臺(tái)下的 char short int 等。為了便于理解,我將其翻譯為普通類型并展示在了源碼的右側(cè)。同時(shí)還把其中的宏函數(shù) ZEND_ENDIAN_LOHI_3() 也展開(kāi)了。

typedef struct _zval_struct zval;
...
       《源代碼》                                               《翻譯后》
-------------------------------------------------------------------------------------------
struct _zval_struct {                               | struct _zval_struct {
    zend_value value;                               |     zend_value value;
    union {                                         |     union {
        struct {                                    |         struct {
            ZEND_ENDIAN_LOHI_3(                     |             unsigned char type;
                zend_uchar type,                    |             unsigned char type_flags;
                zend_uchar type_flags,              |             union {
                union {                             |                 unsigned short extra;
                    uint16_t extra;                 |             } u;
                } u                                 |         } v;
            )                                       |         unsigned int type_info;
        } v;                                        |     } u1;
        uint32_t type_info;                         |     union {
    } u1;                                           |         unsigned int next;
    union {                                         |         unsigned int cache_slot;
        uint32_t next;                              |         unsigned int opline_num;
        uint32_t cache_slot;                        |         unsigned int lineno;
        uint32_t opline_num;                        |         unsigned int num_args;
        uint32_t lineno;                            |         unsigned int fe_pos;
        uint32_t num_args;                          |         unsigned int fe_iter_idx;
        uint32_t fe_pos;                            |         unsigned int access_flags;
        uint32_t fe_iter_idx;                       |         unsigned int property_guard;
        uint32_t access_flags;                      |         unsigned int constant_flags;
        uint32_t property_guard;                    |         unsigned int extra;
        uint32_t constant_flags;                    |     } u2;
        uint32_t extra;                             | };
    } u2;                                           |
};                                                  |

在 zval 結(jié)構(gòu)體中,變量的值就存儲(chǔ)在 zend_value 類型的 value 屬性中。并通過(guò) u1.v.type 來(lái)記錄這個(gè)值是什么類型的,比如 IS_LONG 對(duì)應(yīng)整型,IS_STRING 對(duì)應(yīng)字符串類型。

zend_value 聯(lián)合體

zend_value 類型也是在 php-src/Zend/zend_types.h 中定義的,是一個(gè)聯(lián)合體,下面是 zend_value 聯(lián)合體的定義,左側(cè)是源碼。同樣在右側(cè)我也做了簡(jiǎn)單的翻譯,把 zend_long uint32_t 翻譯為普通類型便于查看。

            《源代碼》                                              《翻譯后》
------------------------------------------------------------------------------------
typedef union _zend_value {                         | typedef union _zend_value {
    zend_long         lval; /* long value */        |     long              lval;
    double            dval; /* double value */      |     double            dval;
    zend_refcounted  *counted;                      |     zend_refcounted  *counted;
    zend_string      *str;                          |     zend_string      *str;
    zend_array       *arr;                          |     zend_array       *arr;
    zend_object      *obj;                          |     zend_object      *obj;
    zend_resource    *res;                          |     zend_resource    *res;
    zend_reference   *ref;                          |     zend_reference   *ref;
    zend_ast_ref     *ast;                          |     zend_ast_ref     *ast;
    zval             *zv;                           |     zval             *zv;
    void             *ptr;                          |     void             *ptr;
    zend_class_entry *ce;                           |     zend_class_entry *ce;
    zend_function    *func;                         |     zend_function    *func;
    struct {                                        |     struct {
        uint32_t w1;                                |         unsigned int w1;
        uint32_t w2;                                |         unsigned int w2;
    } ww;                                           |     } ww;
} zend_value;                                       | } zend_value;

聯(lián)合體的一個(gè)特點(diǎn)是其占用的內(nèi)存是其屬性中最大類型對(duì)應(yīng)的長(zhǎng)度。其中的 zend_long 就是 long 類型,可以看到 long 類型的 lval 和 double 類型的 dval 占用的長(zhǎng)度都是 8 個(gè)字節(jié)。里面其他指針類型,也均為 8 個(gè)字節(jié)。最后面的結(jié)構(gòu)體屬性 ww 是由兩個(gè) int 型構(gòu)成,長(zhǎng)度相加也是 8 個(gè)字節(jié)。因此此聯(lián)合體的長(zhǎng)度為 8 個(gè)字節(jié)。

在我們寫的 PHP 代碼中,整型和浮點(diǎn)型數(shù)據(jù)的值會(huì)直接存放到 lval 和 dval 中。如果是字符串、數(shù)組以及其他類型時(shí)會(huì)開(kāi)辟一段空間存儲(chǔ)數(shù)據(jù),并將其地址存放在 zend_value 中,也就是 zval.value 屬性,如:zval.value.zend_long = 9527、zval.value.zend_string = 字符串地址 、zval.value.zend_array = 數(shù)組地址。然后在 zval.u1.v.type 上標(biāo)記這個(gè) zval.value 是整型、或浮點(diǎn)型、或字符串、或其他類型。

zval.u1.v.type 類型定義也是在 php-src/Zend/zend_types.h 文件中,全部的定義如下:

/* regular data types */
#define IS_UNDEF        0
#define IS_NULL         1
#define IS_FALSE        2
#define IS_TRUE         3
#define IS_LONG         4
#define IS_DOUBLE       5
#define IS_STRING       6
#define IS_ARRAY        7
#define IS_OBJECT       8
#define IS_RESOURCE     9
#define IS_REFERENCE    10
/* constant expressions */
#define IS_CONSTANT_AST 11
/* internal types */
#define IS_INDIRECT     13
#define IS_PTR          14
#define IS_ALIAS_PTR    15
#define _IS_ERROR       15
/* fake types used only for type hinting (Z_TYPE(zv) can not use them) */
#define _IS_BOOL        16
#define IS_CALLABLE     17
#define IS_ITERABLE     18
#define IS_VOID         19
#define _IS_NUMBER      20

zval 結(jié)構(gòu)體內(nèi)存占用

接下來(lái)我們分析一下 zval 所需占用的內(nèi)存。

  • value:zend_value 類型 8 個(gè)字節(jié)。

  • u1:

  • u1.v.type:unsigned char 1 個(gè)字節(jié),u1.v.type_flags:unsigned char 1 個(gè)字節(jié),u1.v.u:聯(lián)合體中只有一個(gè) unsigned short 的 extra 屬性 2 個(gè)字節(jié),因此 u1.v 的結(jié)構(gòu)體總共是 4 個(gè)字節(jié)。

  • u1.type_info:unsigned int 4 個(gè)字節(jié)。

  • 因此 u1 這個(gè)聯(lián)合體的長(zhǎng)度取最長(zhǎng)的屬性的長(zhǎng)度:4 個(gè)字節(jié)。

  • u2:也是一個(gè)聯(lián)合體,里面都是 int 型的屬性,因此長(zhǎng)度是 4 個(gè)字節(jié)。

  • 所以 zval 總共占用的內(nèi)存是 8 + 4 + 4 = 16 個(gè)字節(jié)。

也就是說(shuō)當(dāng)我們?cè)趯?PHP 代碼時(shí),如果創(chuàng)建了一個(gè)整型的變量,那么實(shí)際上它在運(yùn)行中會(huì)占用 16 個(gè)字節(jié)的內(nèi)存,內(nèi)存開(kāi)銷至少是 C 語(yǔ)言的兩倍。當(dāng)然這兩倍的開(kāi)銷也帶來(lái)了 PHP 處理變量的靈活性。

到此,相信大家對(duì)“PHP是怎么存儲(chǔ)變量的”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

文章標(biāo)題:PHP是怎么存儲(chǔ)變量的
分享鏈接:http://bm7419.com/article12/isgidc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、品牌網(wǎng)站建設(shè)軟件開(kāi)發(fā)、網(wǎng)站制作、做網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)