深入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内核之数组的更多相关文章
- php内核之数组
1.zend_hash_num_elements 获取数组元素个数.宏定义如下: #define zend_hash_num_elements(ht) \ (ht)->nNumOfElement ...
- [翻译] Linux 内核中的位数组和位操作
目录 Linux 内核里的数据结构 原文链接与说明 Linux 内核中的位数组和位操作 位数组声明 体系结构特定的位操作 通用位操作 链接 Linux 内核里的数据结构 原文链接与说明 https:/ ...
- Netlink 内核实现分析 2
netlink 应用层如何创建socket 应用层通过socket()系统调用创建Netlink套接字,socket系统调用的第一个参数可以是AF_NETLINK或PF_NETLINK(在Linux系 ...
- kernel编程规范
1. 制表符8个空格2. 每行最长80字符3. 代码块的{放在首行,但是函数的{放在次行4. 只有一行的if块,不加{}5. 不在()前后加空格6. 正常关键字后加一个空格,if, switch, c ...
- select、poll、epoll三组IO复用
int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout)//其中n ...
- Linux中的IO复用接口简介(文件监视?)
I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux ...
- Linux Platform驱动模型(二) _驱动方法
在Linux设备树语法详解和Linux Platform驱动模型(一) _设备信息中我们讨论了设备信息的写法,本文主要讨论平台总线中另外一部分-驱动方法,将试图回答下面几个问题: 如何填充platfo ...
- Linux Platform驱动模型(二) _驱动方法【转】
转自:http://www.cnblogs.com/xiaojiang1025/archive/2017/02/06/6367910.html 在Linux设备树语法详解和Linux Platform ...
- 嵌入式:UCOSIII的使用(17.01.24补充)
0.一些移植.系统相关 OS_CFG_APP.H /* --------------------- MISCELLANEOUS ------------------ */ #define OS_CFG ...
随机推荐
- Memcached 集群架构方面的问题
* 集群架构方面的问题 o memcached是怎么工作的? o memcached最大的优势是什么? o memcached和MySQL的query cache相比,有什么优缺点? o memca ...
- MiniGUI ial 移植指南
MiniGUI ial 移植指南 2.1 ial的定义 ial是一个通用的抽象输入接口,可以输入统一的数据的结构,也就是说在MiniGUI的核心代码里输入的数据的格式是固定的,不管输入设备是鼠标 还是 ...
- C++经典排序算法总结
转发请注明出处:https://www.cnblogs.com/fnlingnzb-learner/p/9374732.html 最近在研究一些经常用到的东西想把它们做一个汇总,想了想用到最多的应该是 ...
- Informatica 常用组件Lookup之九 配置未连接的查找转换
在映射中,未连接的查找转换与管道是分开的.您可以使用 :LKP 引用限定符编写表达式以调用其它转换中的查找.未连接查找的常用用法包括: 测试表达式中某个查找的结果 基于查找结果过滤行 基于查找的结果将 ...
- Cesium中Homebutton改变默认跳转位置 【转】
在Cesium中,Homebutton的默认跳转位置是美国,那么在开发中我们如何更改这个默认跳转位置呢,这就要更改一下源代码了: Camera.DEFAULT_VIEW_RECTANGLE = Rec ...
- Balanced Binary Tree leetcode java
题目: Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced bin ...
- HDU OJ Digital Roots 题目1013
/*Digital Roots Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- RAID5工作原理介绍
RAID 5是一种存储性能.数据安全和存储成本兼顾的存储解决方案.以四个硬盘组成的RAID 5为例,其数据存储方式如图4所示:图中,P0为D0,D1和D2的奇偶校验信息,P1为D3,D4,D5的奇偶校 ...
- (LeetCode 86)Partition List
Given a linked list and a value x, partition it such that all nodes less than x come before nodes gr ...
- CheeseZH: Stanford University: Machine Learning Ex2:Logistic Regression
1. Sigmoid Function In Logisttic Regression, the hypothesis is defined as: where function g is the s ...