Maison  >  Article  >  développement back-end  >  Analyse du code source du noyau sous-jacent PHP8 - tableau (2)

Analyse du code source du noyau sous-jacent PHP8 - tableau (2)

藏色散人
藏色散人avant
2021-06-10 14:50:132513parcourir

Cet article vous présente "Analyse du code source du noyau sous-jacent PHP8 - tableau (2)". Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.

Articles connexes recommandés : "Analyse du code source du noyau sous-jacent PHP8 - tableau (1) " "Analyse du code source du noyau sous-jacent PHP8 - tableau (3) " " Analyse du code source du noyau sous-jacent PHP8 - tableau (4)

zend_array est divisé en deux types en PHP

1.packed array
2.hash array

在上文中 补齐了zend_array的 所有值的 注释

En fait, l'ordre dans le code source est légèrement différent de l'ordre que j'ai mentionné ci-dessus. Je pense que l'ordre que j'ai mentionné ci-dessus est plus raisonnable à comprendre

//源码里的代码
typedef struct _zend_array HashTable;
struct _zend_array {
zend_refcounted_h gc;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar    flags,
zend_uchar    _unused,
zend_uchar    nIteratorsCount,
zend_uchar    _unused2)
} v;
uint32_t flags;
} u;
uint32_t          nTableMask;
Bucket           *arData;
uint32_t          nNumUsed;
uint32_t          nNumOfElements;
uint32_t          nTableSize;
uint32_t          nInternalPointer;
zend_long         nNextFreeElement;
dtor_func_t       pDestructor;
};
//我调换下顺序后的代码
struct _zend_array {
zend_refcounted_h gc; 
 ///  gc  占用8个字节 用于引用计数和  字符串类型的记录
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar    flags,
// flags   8位的无符号字符, 最大值为255   标记HashTable用 PHP8 中有6个值
zend_uchar    _unused,
zend_uchar    nIteratorsCount,
//迭代器计数。foreach语句会在全局变量EG中创建一个迭代器,
//迭代器包含正在遍历的HashTable和游标信息。
//nIteratorsCount记录了当前runtime正在迭代当前HashTable的迭代器的数量。
zend_uchar    _unused2)
} v;
  //这里有点不一样 看陈雷大佬书中 v结构体还包括 u.v.nApplyCount和u.v.consistency
uint32_t flags;
             //
} u;
// u是是一个联合体。占用4个字节。
//可以存储一个uint32_t类型的flags,也可以存储由4个unsigned char组成的结构体v,
//这里的宏ZEND_ENDIAN_LOHI_4是为了兼容不同操作系统的大小端,可以忽略。
Bucket           *arData;
//HashTable中存储数据的单元的指针。
//  用来存储key和value以及辅助信息的容器。
uint32_t          nTableSize;
//    HashTable的大小。表示arData指向的bucket数组的大小,即所有bucket的数量。
//该字段取值始终是2n,最小值是8,最大值在64位系统中是0x80000000(2的31次幂)。
uint32_t          nNumUsed;
//指所有已使用bucket的数量,包括有效bucket和无效bucket的数量
uint32_t          nNumOfElements;
//有效bucket的数量。该值总是小于或等于nNumUsed
uint32_t          nTableMask;
//索引大小。一般值为  -nTableSize。
uint32_t          nInternalPointer;
//全局默认游标。reset/key/current/next/prev等宏 和操作都会用到
zend_long         nNextFreeElement;
//下一个插入的元素的key的下标  
//比如  当$a[] = 1  nNextFreeElement =1  
dtor_func_t       pDestructor;
//指向一个函数   typedef void (*dtor_func_t)(zval *pDest);
//可以看出是pDest是zval结构指针二级指针,
//为什么会是二级指针,因为c语言函数传递都是值传递,要改变指针值只能将指针地址传入
//当bucket元素被更新或者被删除时,会对bucket的value调用该函数,
//如果value是引用计数的类型,那么会对value引用计数减1,进而引发可能的gc。
};
Le diagramme de variables membres généré par l'outil de compréhension est le suivant

Analyse du code source du noyau sous-jacent PHP8 - tableau (2)

Développez tout comme suit

Analyse du code source du noyau sous-jacent PHP8 - tableau (2)

membre de la structure zend_array

On peut voir que le noyau est z_val +zend_string + zend_refcounted_h+Bucket est couche par couche

Le Bucket stocke les informations clés du tableau

typedef struct _Bucket {
zval              val;   //数组的值 ( 复习下 zval只有16个字节)
zend_ulong         h;     // key的 h  值
zend_string      *key;      //当数组为 hash_array时候 会用到 也就是 key的值  
} Bucket;

Quel que soit le type de tableau emballé_array ou hash_array, il sera finalement stocké dans le Bucket In

lorsque les clés sont toutes des touches numériques et que les clés augmentent en insertion dans l'ordre, le type de tableau est

packed_array

packed array Caractéristiques

  1. Pas besoin d'indexer le tableau
  2. Pas besoin de clé
  3. Tableau sans clé La valeur h est directement égale à la valeur de tri de l'espace dans le bucket à partir de 0
  4. Le tableau de paires clé-valeur La valeur h est égale au contenu de la clé

Vous pouvez comprendre les troisième et quatrième éléments comme si vous n'écrivez pas de clé dans le tableau en PHP, alors les clés par défaut seront triées à partir de 0

$a =array(1,2,3);  // packed array
$b =array(1=>'a',3=>'b',5=>'c'); //packed array
Analyse du code source du noyau sous-jacent PHP8 - tableau (2)

Il y aura un tableau d'index avant le tableau de buckets

Quand il s'agit d'un tableau compacté, la taille du tableau d'index est toujours de 2 car Ce n'est pas nécessaire

Le contenu du zend_array correspondant à $a ci-dessus est

Analyse du code source du noyau sous-jacent PHP8 - tableau (2)Le zend_array de $a
nTableSize; représente la taille du tableau de compartiments pointé par arData, c'est-à-dire le nombre de tous les compartiments. =La taille totale du tableau

nNumUsed; Fait référence au nombre de tous les buckets utilisés, y compris le nombre de buckets valides et invalides

🎜> nNumOfElements ; Le nombre de compartiments valides.

Donc nNumOfElements+nNumUsed =nTableSize

nTableMask ; Parce que le tableau compressé n'utilise pas d'index, il est toujours -2

nNextFreeElement; L'indice de la clé du prochain élément inséré

le tableau compressé profite des caractéristiques de continuité du bucket tableau. Pour certaines optimisations pour les scénarios avec uniquement des clés numériques. Étant donné que le tableau d'index n'est plus nécessaire, les octets (nTableSize-2)* sizeof(uint32_t) sont enregistrés à partir de l'espace mémoire. De plus, étant donné que l'accès au compartiment fait fonctionner directement le réseau de compartiments, les performances sont également améliorées.

Si les conditions du tableau compressé ne sont pas remplies, le tableau est représenté par hash_array en PHP

Toutes les valeurs clés qui ne sont pas numériques sont représentées par hash_array

$c =array('x'=>1,'y'=>2,'z'=>3,'a'=>0);

Le $c ci-dessus sera représenté par hash_array comme

bucket comme suit

Analyse du code source du noyau sous-jacent PHP8 - tableau (2)
$ c bucket

zend_array est le suivant

Analyse du code source du noyau sous-jacent PHP8 - tableau (2)
$c zend_array

nTableSize; représente la taille du tableau de buckets pointé par arData, c'est-à-dire le nombre de tous les buckets. =8

nNumUsed; Il fait référence au nombre de buckets utilisés, y compris le nombre de buckets valides et invalides =4

nNumOfElements; de compartiments valides. =4

Donc nNumOfElements+nNumUsed =nTableSize

nTableMask ; -8

nNextFreeElement; L'indice de la clé du prochain élément inséré hash_array sera toujours 0 s'il n'est pas utilisé

▏Cet article a été approuvé par l'auteur original PHP Cui Xuefeng et publié sur le site php chinois, adresse originale : https://zhuanlan.zhihu.com/p/358354087

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