How does PHP store variables? Do you understand the zval structure?

藏色散人
Release: 2023-04-11 06:34:02
forward
4610 people have browsed it

zval in PHP source code

There is no need to declare a type when defining a variable in PHP. Initially, an integer value is assigned to the variable $a, and it can be easily changed to other types later. . So how is this variable $a stored in the PHP source code? With this question in mind, let’s take a look at the source code of PHP.

The source code of PHP is written in C. A zval structure is used in the PHP source code to store the variables created in the PHP code. Let’s take out the definition of the zval structure and briefly analyze it.

This is PHP’s official repository on Github: github.com/php/php-src. The branch used in this article is PHP-7.4.29.

zval structure

Find this file in the PHP source code: php-src/Zend/zend_types.h, you can see that the zval structure is defined as follows , the left side is the source code. The source code uses PHP's own defined types zend_uchar, uint16_t, uint32_t, etc. These types will be converted to char short int, etc. under different platforms and compilers for the platform. For ease of understanding, I translated it into a common type and displayed it on the right side of the source code. At the same time, the macro function ZEND_ENDIAN_LOHI_3() is also expanded.

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;                                           |
};                                                  |
Copy after login

In the zval structure, the value of the variable is stored in the value attribute of the zend_value type. And use u1.v.type to record the type of this value. For example, IS_LONG corresponds to the integer type, and IS_STRING corresponds to the string type.

zend_value union

zend_value type is also defined in php-src/Zend/zend_types.h. It is a union. The following is the definition of zend_value union. , the left side is the source code. Also on the right side, I also made a simple translation, translating zend_long uint32_t into a common type for easy viewing.

            《源代码》                                              《翻译后》
------------------------------------------------------------------------------------
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;
Copy after login

One characteristic of the union is that the memory it occupies is the length corresponding to the largest type in its attributes. Among them, zend_long is of type long. You can see that the length of lval of long type and dval of double type are both 8 bytes. Other pointer types inside are also 8 bytes. The last structure attribute ww is composed of two int types, and the combined length is also 8 bytes. The length of this union is therefore 8 bytes.

In the PHP code we write, the values ​​of integer and floating point data will be stored directly in lval and dval. If it is a string, array or other types, a space will be allocated to store the data, and its address will be stored in zend_value, which is the zval.value attribute, such as: zval.value.zend_long = 9527, zval.value.zend_string = character String address, zval.value.zend_array = array address. Then mark on zval.u1.v.type that this zval.value is an integer, floating point, string, or other type.

zval.u1.v.type type definition is also in the php-src/Zend/zend_types.h file. All definitions are as follows:

/* 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
Copy after login

zval structure memory usage

Next we analyze the memory required by zval.

  • value: zend_value type 8 bytes.

  • u1:

  • u1.v.type: unsigned char 1 byte, u1.v.type_flags : unsigned char 1 byte, u1.v.u: There is only one unsigned short extra attribute in the union of 2 bytes, so the structure of u1.v is 4 bytes in total.

  • u1.type_info: unsigned int 4 bytes.

  • So the length of the union u1 is the length of the longest attribute: 4 bytes.

  • u2: It is also a union, which contains int-type attributes, so the length is 4 bytes.

  • So the total memory occupied by zval is 8 4 4 = 16 bytes.

That is to say, when we write PHP code, if we create an integer variable, it will actually occupy 16 bytes of memory during operation, memory overhead At least twice as long as C language. Of course, this double overhead also brings PHP's flexibility in handling variables.

Recommended learning: "PHP Video Tutorial"

The above is the detailed content of How does PHP store variables? Do you understand the zval structure?. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:learnku.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template