Maison  >  Article  >  développement back-end  >  Comment PHP stocke-t-il les variables ? Comprenez-vous la structure de zval ?

Comment PHP stocke-t-il les variables ? Comprenez-vous la structure de zval ?

藏色散人
藏色散人avant
2022-05-26 09:47:254608parcourir

zval dans le code source PHP

Lors de la définition d'une variable en PHP, il n'est pas nécessaire de déclarer un type. Initialement, une valeur entière est attribuée à la variable $a, et elle peut être facilement modifiée par d'autres types ultérieurement. Alors, comment cette variable $a est-elle stockée dans le code source PHP ? En gardant cette question à l’esprit, jetons un coup d’œil au code source de PHP.

Le code source de PHP est écrit en C. Une structure zval est utilisée dans le code source PHP pour stocker les variables créées dans le code PHP. Reprenons la définition de la structure zval et analysons-la brièvement.

Il s'agit du référentiel officiel de PHP sur Github : github.com/php/php-src La branche utilisée dans cet article est PHP-7.4.29.

Structure zval

Retrouvez ce fichier dans le code source PHP : php-src/Zend/zend_types.h Vous pouvez voir que la structure zval est définie comme suit, avec le code source à gauche. Le code source utilise les types définis par PHP, zend_uchar, uint16_t, uint32_t, etc. Ces types seront convertis en char short int, etc. sous différentes plates-formes et compilateurs pour la plate-forme. Pour faciliter la compréhension, je l'ai traduit en un type commun et je l'ai affiché sur le côté droit du code source. Dans le même temps, la fonction macro ZEND_ENDIAN_LOHI_3() est également étendue.

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;                                           |
};                                                  |

Dans la structure zval, la valeur de la variable est stockée dans l'attribut value du type zend_value. Et utilisez u1.v.type pour enregistrer le type de cette valeur. Par exemple, IS_LONG correspond au type entier et IS_STRING correspond au type chaîne.

union zend_value

Le type zend_value est également défini dans php-src/Zend/zend_types.h C'est une union Ce qui suit est la définition de l'union zend_value, et le code source est à gauche. Également sur le côté droit, j'ai également fait une traduction simple, traduisant zend_long uint32_t en un type commun pour une visualisation facile.

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

Une caractéristique de l'union est que la mémoire qu'elle occupe est la longueur correspondant au plus grand type dans ses attributs. Parmi eux, zend_long est de type long. Vous pouvez voir que la longueur de lval de type long et dval de type double est toutes deux de 8 octets. Les autres types de pointeurs à l'intérieur font également 8 octets. Le dernier attribut de structure ww est composé de deux types int et la longueur combinée est également de 8 octets. La longueur de cette union est donc de 8 octets.

Dans le code PHP que nous écrivons, les valeurs des données entières et à virgule flottante seront stockées directement dans lval et dval. S'il s'agit d'une chaîne, d'un tableau ou d'un autre type, un espace sera alloué pour stocker les données, et son adresse sera stockée dans zend_value, qui est l'attribut zval.value, tel que : zval.value.zend_long = 9527, zval .value.zend_string = adresse de chaîne de caractères, zval.value.zend_array = adresse de tableau. Marquez ensuite sur zval.u1.v.type que ce zval.value est un entier, une virgule flottante, une chaîne ou un autre type.

La définition du type zval.u1.v.type se trouve également dans le fichier 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

Utilisation de la mémoire de la structure zval

Ensuite, analysons ce dont zval a besoin. mémoire occupée.

  • value : zend_value tapez 8 octets.

  • u1 :

  • u1.v.type : caractère non signé 1 octet, u1.v.type_flags : caractère non signé 1 octet, u1.v.u : Il n'y a qu'un seul court non signé dans l'union L'attribut supplémentaire est de 2 octets, donc la structure de u1.v est de 4 octets au total.

  • u1.type_info : entier non signé 4 octets.

  • Donc la longueur de l'union u1 est la longueur de l'attribut le plus long : 4 octets.

  • u2 : C'est aussi une union, qui contient des attributs de type int, donc la longueur est de 4 octets.

  • Donc la mémoire totale occupée par zval est de 8 + 4 + 4 = 16 octets.

C'est-à-dire que lorsque nous écrivons du code PHP, si nous créons une variable entière, elle occupera en fait 16 octets de mémoire pendant le fonctionnement, et la surcharge de mémoire est au moins deux fois supérieure à celle du langage C. Bien entendu, cette double surcharge apporte également la flexibilité de PHP dans la gestion des variables.

Apprentissage recommandé : "Tutoriel vidéo PHP"

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer