Maison > Article > développement back-end > Comment PHP stocke-t-il les variables ? Comprenez-vous la structure de zval ?
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!