博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入PHP内核之数组
阅读量:4694 次
发布时间:2019-06-09

本文共 6675 字,大约阅读时间需要 22 分钟。

定义:

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

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

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

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

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

我们看一下PHP定义数组

 在内核中

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, __length, __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);  }

 

转载于:https://www.cnblogs.com/chenpingzhao/p/4684651.html

你可能感兴趣的文章
【Python求助】在eclipse和pycharm中,通过adb install安装中文名字APK时老是报错,如何解决...
查看>>
用weka来做Logistic Regression
查看>>
Linux现学现用之Top命令
查看>>
[C3W1] Structuring Machine Learning Projects - ML Strategy 1
查看>>
【原创】谈谈服务雪崩、降级与熔断
查看>>
Java加密代码 转换成Net版
查看>>
jquery.validation.js 使用
查看>>
day38 mycql 初识概念,库(增删改查),表(增删改)以及表字段(增删改查),插入更新操作...
查看>>
数据库高级查询
查看>>
C语言实现封装、继承和多态
查看>>
Linux字符设备驱动框架(二):Linux内核的LED设备驱动框架
查看>>
创建文件
查看>>
Nginx 相关介绍
查看>>
leetcode[33]Search in Rotated Sorted Array
查看>>
安卓上按钮绑定监听事件的两种写法
查看>>
OpenCV Shi-Tomasi角点检测子
查看>>
jQurey基础简介
查看>>
GCC 提供的原子操作
查看>>
从RGB色转为灰度色算法
查看>>
ubuntu两个conda安装和切换
查看>>