zoukankan      html  css  js  c++  java
  • PHP内核之旅-5.强大的数组

    PHP 内核之旅系列

    一、数组的内部结构

    1.底层实现为散列表(HashTable,也称作哈希表)

    2.散列表的概念:

    是根据关键码值(Key value)而直接进行访问的数据结构。通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。复杂度为O(1)。

    文件路径endzend_types.h

    _zend_array结构:

     1 typedef struct _zend_array zend_array;
     2 typedef struct _zend_array HashTable;
     3 
     4 struct _zend_array {
     5     zend_refcounted_h gc;
     6     union {
     7         struct {
     8             ZEND_ENDIAN_LOHI_4(
     9                 zend_uchar    flags,
    10                 zend_uchar    nApplyCount,
    11                 zend_uchar    nIteratorsCount,
    12                 zend_uchar    consistency)
    13         } v;
    14         uint32_t flags;
    15     } u;
    16     uint32_t          nTableMask;
    17     Bucket           *arData;
    18     uint32_t          nNumUsed;
    19     uint32_t          nNumOfElements;
    20     uint32_t          nTableSize;
    21     uint32_t          nInternalPointer;
    22     zend_long         nNextFreeElement;
    23     dtor_func_t       pDestructor;
    24 };

    zend_array和HashTable结构相同 

    arData:散列表中保存存储元素的数组,其内存是连续的,arData指向数组的起始位置,其内存连续。

    nTableSize:数组的总容量,可以容纳的元素数,大小是2的幂次方,最小为8

    nTableMask: 映射元素的存储位置用到,nTableSize的负数

    nNumUsed: 数组当前使用的Bucket数,删除元素时,不会将其从数组中移除,将这个元素的类型标为IS_UNDEF,当数组容量超限,扩容时才会删除。

    nNumOfElements:数组中有效元素的位置

    nNextFreeElement:下一个数值的索引

    pDestructor:删除或覆盖数组中的某个元素时,则调用此函数对旧元素进行处理

    u:辅助作用

    Bucket结构:

    1 typedef struct _Bucket {
    2     zval              val;
    3     zend_ulong        h;                /* hash value (or numeric index)   */
    4     zend_string      *key;              /* string key or NULL for numerics */
    5 } Bucket;

     val: 具体的value

     h: key的hash值,或者数值索引

    *key: 存储元素的key,如果元素是数值索引则为NULL

    二、数组的基本实现

    散列函数:将元素进行hash运算后的值,对数组大小取模之后的值(下标:0~7)分配到中间映射表

    中间映射表:元素和下标的映射关系表。可以通过arData向前访问到

    元素数组:实际存储元素的数组,按照下标有序存储元素

    三、数组的初始化

    endzend_hash.c

     1 ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
     2 {
     3     GC_REFCOUNT(ht) = 1;
     4     GC_TYPE_INFO(ht) = IS_ARRAY | (persistent ? 0 : (GC_COLLECTABLE << GC_FLAGS_SHIFT));
     5     ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS;
     6     ht->nTableMask = HT_MIN_MASK;
     7     HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
     8     ht->nNumUsed = 0;
     9     ht->nNumOfElements = 0;
    10     ht->nInternalPointer = HT_INVALID_IDX;
    11     ht->nNextFreeElement = 0;
    12     ht->pDestructor = pDestructor;
    13     ht->nTableSize = zend_hash_check_size(nSize);
    14 }

    endzend_API.c

    1 ZEND_API int _array_init(zval *arg, uint32_t size ZEND_FILE_LINE_DC) /* {{{ */
    2 {
    3     ZVAL_NEW_ARR(arg);
    4     _zend_hash_init(Z_ARRVAL_P(arg), size, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
    5     return SUCCESS;
    6 }

     四、插入

    插入时首先会检查数组已经分配存储空间,初始化时没有实际分配arData的内存,第一次插入时才会根据nTableSize的大小分配,分配完以后会把HashTable->u.flags打上HASH_FLAG_INITIALIZED掩码,下次插入时发现已经分配了就不会再重复操作。

     1 static zend_always_inline void zend_hash_check_init(HashTable *ht, int packed)
     2 {
     3     HT_ASSERT_RC1(ht);
     4     if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) {
     5         zend_hash_real_init_ex(ht, packed);
     6     }
     7 }
     8 
     9 #define CHECK_INIT(ht, packed) 
    10     zend_hash_check_init(ht, packed)

    参考资料:

    http://www.php-internals.com/

    PHP7内核剖析


    作  者: Jackson0714
    出  处:http://www.cnblogs.com/jackson0714/
    关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教!
    版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
    特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

  • 相关阅读:
    数据库删除Push
    MFC Tab Control控件的详细使用
    mysql char和varchar的长度
    PostgreSQL常用脚本
    Linux常用操作命令
    PostgreSQL杀掉会话
    PostgresSQL备份还原
    Grpc客户端添加请求头(Header)
    Polly重试
    名词探疑3:I18N,L10N,A11Y
  • 原文地址:https://www.cnblogs.com/jackson0714/p/php5.html
Copyright © 2011-2022 走看看