Maison  >  Article  >  développement back-end  >  Noyau PHP zval

Noyau PHP zval

不言
不言original
2018-04-19 09:26:152708parcourir

Le contenu principal de cet article concerne le zval du noyau PHP, qui a une certaine valeur de référence. Maintenant, je le partage avec tout le monde. Les amis dans le besoin peuvent s'y référer

Adresse originale
. Auteur : Page d'accueil de Twei

Avant-propos


Lors de l'entretien précédent, l'intervieweur a demandé comment les variables sont implémentées en PHP. Malheureusement, il a seulement répondu que cela était probablement implémenté à l'aide d'une structure. Cet article a été assez bien résumé d'après Google, je l'ai donc réimprimé et étudié.

Texte


Types de données en PHP


Par rapport à d'autres langages de programmation tels que C, C++, Java, etc., PHP est un langage faiblement typé ce qui signifie que lorsque l'on veut utiliser une variable, on n'a pas besoin de déclarer son type. Cette fonctionnalité nous apporte beaucoup de commodité, mais elle comporte parfois aussi quelques pièges. Alors, PHP n’a-t-il vraiment aucun type de données ?

Bien sûr que non. Dans la documentation officielle PHP, les variables PHP sont divisées en trois catégories : les types scalaires, les types complexes et les types spéciaux. Les types scalaires incluent bool, int, float et string ; les types complexes incluent les tableaux et les objets ; les types spéciaux incluent NULL et resources . Ainsi, en termes de répartition des variables PHP, il existe 8 types de données.

Comme nous le savons tous, la couche inférieure de PHP est implémentée en langage C. Notre script PHP sera analysé en code C par le moteur Zend puis exécuté. Alors, comment une variable PHP est-elle représentée en langage C ? En quoi sera-t-il finalement analysé ?

La réponse est zval. Quel que soit le type de variable PHP, elle est uniformément représentée par une structure appelée zval dans le code source PHP. zval peut être considéré comme un conteneur pour les variables PHP dans le code C. Il stocke la valeur, le type et d'autres informations associées de cette variable.

Jetons ensuite un œil à la structure de base de zval (nécessite quelques connaissances de base du langage C).

Structure de base de zval


Dans le code source PHP, la structure de zval est une structure (struct) nommée _zval_struct, qui est spécifiquement définie dans Dans le fichier Zend/zend.h du code source, voici un extrait du code pertinent :

struct _zval_struct {
    zvalue_value value;       /* value */ 
    zend_uint refcount__gc;   /* value of ref count */
    zend_uchar type;          /* active type */ 
    zend_uchar is_ref__gc;    /* if it is a ref variable */ }; 
typedef struct _zval_struct zval;

Autrement dit, dans le code source de PHP, cette structure est utilisée pour représenter différents types de variables en PHP. Et il peut également implémenter d'autres fonctions, comme le garbage collection (GC : Grabage Collection).

Vous pouvez voir qu'il se compose de 4 champs, chacun représentant certaines informations sur cette variable.

ZVALUE_VALUE VALUE


value est utilisée pour représenter la valeur réelle de la variable Plus précisément, il s'agit d'une union de zvalue_value :

typedef union _zvalue_value {    long lval;                  /* long value */
    double dval;                /* double value */
    struct {                    /* string */
        char *val;        int len;
    } str;
    HashTable *ht;              /* hash table value,used for array */
    zend_object_value obj;      /* object */} zvalue_value;

Oui Nous voyons. qu'il n'y a que 5 champs dans _zvalue_value, mais il y a 8 types de données en PHP Alors, comment utiliser 5 champs pour représenter 8 types ?

C'est l'un des aspects les plus intelligents de la conception PHP. Il atteint l'objectif de réduire les champs en réutilisant les champs. Par exemple, dans PHP, les types booléens, les entiers et les ressources (tant que l'identifiant de la ressource est stocké) sont stockés via le champ lval ; dval est utilisé pour stocker les types à virgule flottante ; str stocke les chaînes ; en PHP Le tableau est en fait une table de hachage) ; et obj stocke les types d'objets ; si tous les champs sont définis sur 0 ou NULL, cela signifie NULL en PHP, de sorte que 5 champs sont utilisés pour stocker 8 types de valeurs.

ZEND_UINT REFCOUNT__GC


Comme vous pouvez le voir d'après son suffixe gc, ce champ est lié au garbage collection.

C'est en fait un compteur pour enregistrer le nombre de variables pointant vers ce zval. Lorsque la variable est générée, elle est définie sur 1, c'est-à-dire refcount = 1.

Effectuer différentes opérations sur une variable modifiera sa valeur. Les opérations d'affectation typiques telles que

b augmenteront le refcount de 1, et l'opération unset() diminuera de 1 en conséquence.

La collecte des déchets peut être effectuée en jugeant sa valeur. Avant PHP5.3, le mécanisme de comptage de références était utilisé pour implémenter GC : si le refcount d'un zval est réduit à 0, alors le moteur Zend pensera qu'il n'y a aucune variable pointant vers le zval et libérera l'espace mémoire occupé par le zval. Mais la simple utilisation du mécanisme de comptage de références ne peut pas libérer le zval de la référence circulaire, ce qui entraînera une fuite de mémoire (Memory Leak).

Avant la version 5.3, le nom de ce champ s'appelait encore refcount. Après la version 5.3, lorsqu'un nouvel algorithme de garbage collection a été introduit pour gérer les références circulaires, l'auteur a ajouté un grand nombre de macros pour faire fonctionner refcount, afin de traiter les références circulaires. pour rendre les erreurs plus rapides, il a donc été renommé refcount__gc, obligeant tout le monde à utiliser des macros pour faire fonctionner refcount.

De même, il existe un quatrième champ is_ref. Cette valeur indique si un type en PHP est une référence.
Si vous souhaitez en savoir plus sur le mécanisme de récupération de place de PHP, vous pouvez vous référer à ce blog : Le mécanisme de récupération de place de PHP
Remarque : les variables peuvent également être appelées symboles. Tous les symboles existent dans la table des symboles et différentes étendues utilisent différentes tables de symboles. Ce blog explique cela.

ZEND_UCHAR TYPE


这个字段用于表明变量属于 PHP 8 种类型的哪种。在 zend 内部,这些类型对应于下面的宏(代码位置 phpsrc/Zend/zend.h):

#define IS_NULL     0#define IS_LONG     1#define IS_DOUBLE   2#define IS_BOOL     3#define IS_ARRAY    4#define IS_OBJECT   5#define IS_STRING   6#define IS_RESOURCE 7#define IS_CONSTANT 8#define IS_CONSTANT_ARRAY   9#define IS_CALLABLE 10

ZEND_UCHAR IS_REF__GC


这个字段用于标记变量是否是引用变量。对于普通的变量,该值为 0,而对于引用型的变量,该值为 1。这个变量会影响 zval 的共享、分离等。它也和 PHP 的垃圾回收有关。

PHP7中的zval


上述的 zval 结构,随着时间的发展,暴露出许多问题,例如占用空间大(24 字节)、不支持拓展、 对象和引用效率差等,所以在 PHP7 的时候,对 zval 进行了较大的改变,现在它的结构是这样的:

struct _zval_struct {    union {
        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;
    } 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     var_flags;
        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 */
    } u2;
};

虽然看起来变得好大,但其实仔细看,它的字段都是联合体,这个新的 zval 在 64 位环境下,只需要 16 个字节(2 个指针 size)。PHP7 中的 zval,已经变成了一个值指针,它要么保存着原始值,要么保存着指向一个保存原始值的指针。

这部分内容来自鸟哥的GitHub。

总结


  1. zval 是一种 C 语言实现的数据结构,功能是作为 PHP 变量的容器;

  2. 它保存了变量的各种信息(如类型和值),并为其他功能(如垃圾回收)提供支持;

  3. 在不同的 PHP 版本中,它的结构不同。PHP7 的 zval 占 16 个字节,PHP5 的要占 24 个字节。

参考


PHP内核探索之变量(1)变量的容器-Zval
PHP垃圾回收深入理解
深入理解PHP7之zval

相关推荐:

PHP内核之探究内存管理与缓存机制

PHP内核分析-Zend虚拟机详解

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:php-fpm statique dynamiqueArticle suivant:php-fpm statique dynamique