zoukankan      html  css  js  c++  java
  • 深入PHP内核之数组

    定义:

    PHP 中的数组实际上是一个有序映射。映射是一种把 values 关联到 keys 的类型。此类型在很多方面做了优化,因此可以把它当成真正的数组,或列表(向量),散列表(是映射的一种实现),字典,集合,栈,队列以及更多可能性。数组元素的值也可以是另一个数组。树形结构和多维数组也是允许的。

    这是手册中对PHP数组的定义,本质上是一种键-值映射的关系,算是一种散列表(哈希表)。

    到这里我不得不说,PHP内核中的神器了  HashTable

    HashTable即具有双向链表的优点,PHP中的定义的变量保存在一个符号表里,而这个符号表其实就是一个HashTable,它的每一个元素都是一个zval*类型的变量。不仅如此,保存用户定义的函数、类、资源等的容器都是以HashTable的形式在内核中实现的。

    因此,PHP的数组读写都可以在O(1)内完成,这是非常高效的,因此开销和C++、Java相比也就是hashtable的创建了

    我们看一下PHP定义数组

    <?php  
        $array = array();  
        $array["key"] = "value";  
    

     在内核中

    zval* array;  
    array_init(array);  
    add_assoc_string(array, "key", "value", 1);
    

     这样就可以了

    看一下源码是怎么实现

    在zend_API.h 文件中,这是一个宏定义

    #define array_init(arg)                 _array_init((arg), 0 ZEND_FILE_LINE_CC)
    

     接着看,在zend_API.c 文件中

    /* Argument parsing API -- andrei */
    ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC) /* {{{ */
    {
            ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg));
    
            _zend_hash_init(Z_ARRVAL_P(arg), size, NULL, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
            Z_TYPE_P(arg) = IS_ARRAY;
            return SUCCESS;
    }
    /* }}} */
    

    再接着看,在zend_alloc.h文件中

    #define ALLOC_HASHTABLE_REL(ht) 
            (ht) = (HashTable *) emalloc_rel(sizeof(HashTable))
    

     再接着看

    ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_
    FILE_LINE_DC)
    {
            uint i = 3;//初始化是为1<<3=8
    
            SET_INCONSISTENT(HT_OK);
    		//最大个数为1>>31 = 2^31 =2147483648
            if (nSize >= 0x80000000) {
                    /* prevent overflow */
                    ht->nTableSize = 0x80000000;
            } else {
                    while ((1U << i) < nSize) {
                            i++;
                    }
                    ht->nTableSize = 1 << i;
            }
    
            ht->nTableMask = 0;     /* 0 means that ht->arBuckets is uninitialized */
            ht->pDestructor = pDestructor; /* 元素的析构函数(指针) */
            ht->arBuckets = (Bucket**)&uninitialized_bucket;
            ht->pListHead = NULL;  /* 头元素, 用于线性遍历 */
            ht->pListTail = NULL;  /* 尾元素, 用于线性遍历 */
            ht->nNumOfElements = 0; /* HashTable中实际元素的个数 */
            ht->nNextFreeElement = 0; /* 下个空闲可用位置的数字索引 */
            ht->pInternalPointer = NULL; /* 内部位置指针, 会被reset, current这些遍历函数使用 */
    		ht->persistent = persistent;
            ht->nApplyCount = 0;/* 循环遍历保护 */
            ht->bApplyProtection = 1;
            return SUCCESS;
    }
    

     以上是数组初始化可以参考  http://www.laruence.com/2009/08/23/1065.html

    然后赋值的过程

    zval* val;  
    MAKE_STD_ZVAL(val);  
    ZVAL_STRING(val, "value", 0);  
    zend_hash_add(h, "key", 4, &val, sizeof(zval*), NULL);  
    

     内核为我们提供了方便的宏来管理数组

    ZEND_API int add_index_long(zval *arg, ulong idx, long n);
    ZEND_API int add_index_null(zval *arg, ulong idx);
    ZEND_API int add_index_bool(zval *arg, ulong idx, int b);
    ZEND_API int add_index_resource(zval *arg, ulong idx, int r);
    ZEND_API int add_index_double(zval *arg, ulong idx, double d);
    ZEND_API int add_index_string(zval *arg, ulong idx, const char *str, int duplicate);
    ZEND_API int add_index_stringl(zval *arg, ulong idx, const char *str, uint length, int duplicate);
    ZEND_API int add_index_zval(zval *arg, ulong index, zval *value);
    
    ZEND_API int add_next_index_long(zval *arg, long n);
    ZEND_API int add_next_index_null(zval *arg);
    ZEND_API int add_next_index_bool(zval *arg, int b);
    ZEND_API int add_next_index_resource(zval *arg, int r);
    ZEND_API int add_next_index_double(zval *arg, double d);
    ZEND_API int add_next_index_string(zval *arg, const char *str, int duplicate);
    ZEND_API int add_next_index_stringl(zval *arg, const char *str, uint length, int duplicate);
    
    ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, long n);
    ZEND_API int add_assoc_null_ex(zval *arg, const char *key, uint key_len);
    ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, uint key_len, int b);
    ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, uint key_len, int r);
    ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, double d);
    ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char *str, int duplicate);
    ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char *str, uint length, int duplicate);
    ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, uint key_len, zval *value);
    
    #define add_assoc_long(__arg, __key, __n) add_assoc_long_ex(__arg, __key, strlen(__key)+1, __n)
    #define add_assoc_null(__arg, __key) add_assoc_null_ex(__arg, __key, strlen(__key) + 1)
    #define add_assoc_bool(__arg, __key, __b) add_assoc_bool_ex(__arg, __key, strlen(__key)+1, __b)
    #define add_assoc_resource(__arg, __key, __r) add_assoc_resource_ex(__arg, __key, strlen(__key)+1, __r)
    #define add_assoc_double(__arg, __key, __d) add_assoc_double_ex(__arg, __key, strlen(__key)+1, __d)
    #define add_assoc_string(__arg, __key, __str, __duplicate) add_assoc_string_ex(__arg, __key, strlen(__key)+1, __str, __duplicate)
    #define add_assoc_stringl(__arg, __key, __str, __length, __duplicate) add_assoc_stringl_ex(__arg, __key, strlen(__key)+1, __str, __len
    gth, __duplicate)
    #define add_assoc_zval(__arg, __key, __value) add_assoc_zval_ex(__arg, __key, strlen(__key)+1, __value)
    

     具体实现

    $arr[] = NULL;  add_next_index_null(arr);  
    $arr[] = 42;    add_next_index_long(arr, 42);  
    $arr[] = true;  add_next_index_bool(arr, 1);  
    $arr[] = 3.14;  add_next_index_double(arr, 3.14);  
    $arr[] = 'foo'; add_next_index_string(arr, "foo");  
    $arr[] = $var;  add_next_index_zval(arr, zval);  
    
    $arr[0] = NULL; add_index_null(arr, 0);  
    $arr[1] = 42;       add_index_long(arr, 1, 42);  
    $arr[2] = true;     add_index_bool(arr, 2, 1);  
    $arr[3] = 3.14;     add_index_double(arr, 3, 3.14);  
    $arr[4] = 'foo';        add_index_string(arr, 4, "foo", 1);  
    $arr[5] = $var;     add_index_zval(arr, 5, zval); 
    
    $arr["abc"] = NULL; add_assoc_null(arr, "abc");  
    $arr["def"] = 42;   add_assoc_long(arr, "def", 42);  
    $arr["ghi"] = true; add_assoc_bool(arr, "ghi", 1);  
    $arr["jkl"]  = 3.14 add_assoc_double(arr, "jkl", 3.14);  
    $arr["mno"]="foo"   add_assoc_string(arr, "mno", "foo", 1");  
    $arr["pqr"] = $var; add_assoc_zval(arr, "pqr", zval);  
    

     扩展中测试

    PHP_FUNCTION(array_test1)
    {
    	zval *value;
    	zval *element;
    	char *s="This is a test";
    	char *key="a";
    	MAKE_STD_ZVAL(element);
    	MAKE_STD_ZVAL(value);
    	array_init(value);
    	ZVAL_STRING(element,s,strlen(s));
    	zend_hash_update(value->value.ht,key,strlen(key)+1,(void*)&element,sizeof(zval*),NULL);
    	ZEND_SET_SYMBOL(EG(active_symbol_table),"siren",value); 
    }
    
    PHP_FUNCTION(array_test2){  
    	char* str;  
    	zval* subarray;  
    	array_init(return_value);
    	array_init(subarray);  	
    	add_next_index_string(return_value, "test", 1);  
    	str = estrdup("This is a test");  
    	add_next_index_string(return_value, str, 0);  
    	add_assoc_double(return_value, "double", 3.14);  
    	add_next_index_string(subarray, "hello", 1);  
    	add_assoc_zval(return_value, "xsubarray", subarray);  
    }  
    
  • 相关阅读:
    仿微博添加和删除的动画
    到公司实习一个月记
    写一份好简历
    排序算法之快速排序
    PHP和MYSQL中的日期和时间
    我的php经历
    新的征程
    毕业设计笔记
    排序算法之总结
    javascript执行效率小结
  • 原文地址:https://www.cnblogs.com/chenpingzhao/p/4684651.html
Copyright © 2011-2022 走看看