定义:

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内核之数组的更多相关文章

  1. php内核之数组

    1.zend_hash_num_elements 获取数组元素个数.宏定义如下: #define zend_hash_num_elements(ht) \ (ht)->nNumOfElement ...

  2. [翻译] Linux 内核中的位数组和位操作

    目录 Linux 内核里的数据结构 原文链接与说明 Linux 内核中的位数组和位操作 位数组声明 体系结构特定的位操作 通用位操作 链接 Linux 内核里的数据结构 原文链接与说明 https:/ ...

  3. Netlink 内核实现分析 2

    netlink 应用层如何创建socket 应用层通过socket()系统调用创建Netlink套接字,socket系统调用的第一个参数可以是AF_NETLINK或PF_NETLINK(在Linux系 ...

  4. kernel编程规范

    1. 制表符8个空格2. 每行最长80字符3. 代码块的{放在首行,但是函数的{放在次行4. 只有一行的if块,不加{}5. 不在()前后加空格6. 正常关键字后加一个空格,if, switch, c ...

  5. select、poll、epoll三组IO复用

    int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout)//其中n ...

  6. Linux中的IO复用接口简介(文件监视?)

    I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux ...

  7. Linux Platform驱动模型(二) _驱动方法

    在Linux设备树语法详解和Linux Platform驱动模型(一) _设备信息中我们讨论了设备信息的写法,本文主要讨论平台总线中另外一部分-驱动方法,将试图回答下面几个问题: 如何填充platfo ...

  8. Linux Platform驱动模型(二) _驱动方法【转】

    转自:http://www.cnblogs.com/xiaojiang1025/archive/2017/02/06/6367910.html 在Linux设备树语法详解和Linux Platform ...

  9. 嵌入式:UCOSIII的使用(17.01.24补充)

    0.一些移植.系统相关 OS_CFG_APP.H /* --------------------- MISCELLANEOUS ------------------ */ #define OS_CFG ...

随机推荐

  1. table固定首行(二)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. zookeeper 伪分布式安装

    1 下载zookeeper安装包 下载地址 http://apache.fayea.com/zookeeper/ 我下载的是zookeeper-3.4.6.tar.gz 2 解压缩 将zookeepe ...

  3. C语言:通过函数指针来完成两个数的加减乘除

    // //  main.c //  Function_pointer // //  Created by mac on 15/8/2. //  Copyright (c) 2015年. All rig ...

  4. go语言基础之map赋值、遍历、删除 、做函数参数

    1.map赋值 示例: package main //必须有个main包 import "fmt" func main() { m1 := map[int]string{1: &q ...

  5. go语言基础之复合类型

    1.分类 类型 名称 长度 默认值 说明 pointer 指针 nil array 数组 0 slice 切片 nil 引⽤类型 map 字典 nil 引⽤类型 struct 结构体 2.指针 指针是 ...

  6. Python并发编程-Memcached (分布式内存对象缓存系统)

    一.Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的 ...

  7. graphic rendering pipeline

    整理下管线 此时一定要有这张图 注意表中的数据流向 强调几个细节 之前对次序理解有点乱 rasterizer之前 管线里是只有逐顶点信息的 IA里面会setup primitive  通过Primit ...

  8. 检测 USB 设备拨插的 C# 类库:USBClassLibrary

    这是采用C#开发的一个USB库,使您可以管理USB设备的连接和分离事件,探测自己的设备.可以运行在Windows XP和Windows7 64位系统下. 01 private void USBPort ...

  9. 独特的deadlock(仅update语句也能造成死锁)

    最近遇到了一个看上去很奇怪,分析起来很有意思的死锁问题.这个死锁看上去难以理解.而分析过程中,又使用了很多分析SQL Server死锁的典型方法.记录下来整个分析过程还是很有意义的. 问题重现步骤: ...

  10. IOS UITableView拖动排序功能

    UITbableView作为列表展示信息,除了展示的功能,有时还会用到删除,排序等功能,下面就来讲解一下如何实现排序. 排序是当表格进入编辑状态后,在单元格的右侧会出现一个按钮,点击按钮,就可以拖动单 ...