PHP5.3 里面数组的的实现方式
- typedef struct _Bucket
- {
- char *key;
- void *value;
- struct _Bucket *next;
- } Bucket;
- typedef struct _HashTable
- {
- int size; // 哈希表的大小
- int elem_num; // 已经保存元素的个数
- Bucket **buckets;
- } HashTable;
在 HashTable 里面存放这 Bucket 的指针数组,而 Bucket 本身的`*next`是用来解决 hash 冲突的,一个 key 下面对应多个值的情况,就放在一个链表上。
画了我好久,下面这张图
看到一篇文章,正好就是把 php 里面的 hashtable 给抽出来了:http://liuzhiqiangruc.iteye.com/blog/1871334
更加具体详细的介绍:http://www.php-internals.com/book/?p=chapt03/03-01-02-hashtable-in-php
下面是自己的笔记:
php 里所有的变量都存在了结构体_zval_struct
中:
- struct _zval_struct {
- zvalue_value value; // 存储的变量的值
- zend_unit refcount__gc; // 表示引用的次数 默认为1
- zend_uchar type; // 变量具体的类型 IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE 之一
- zend_uchar is_ref_gc; // 表示是否为引用 默认为0
- }
从上面的可以看出,存储的值又存储在联合体`zvalue_value`中:
- typedef union _zvalue_value {
- long lval; /* long value */
- double dval; /* double value */
- struct {
- char *val;
- int len;
- } str;
- HashTable *ht; /* hash table value */
- zend_object_value obj;
- } zvalue_value;
- typedef union _zvalue_value {
而在 php 中数组实际在`_zvalue_value`里存储的就是HashTable
. 上面定义的简单的 hashtable 不足于满足 php 实际复杂业务逻辑的需求,我们需要的功能很多,比如count
,array_pop
,next
,pre
,current
等。所以为了让这些操作更加高效,就选择了用空间换时间的做法,存储更多的字段,存储更多的关联关系。
- typedef struct _hashtable {
- uint nTableSize; // hash Bucket的大小,最小为8,以2x增长。
- uint nTableMask; // nTableSize-1 , 索引取值的优化
- uint nNumOfElements; // hash Bucket中当前存在的元素个数,count()函数会直接返回此值
- ulong nNextFreeElement; // 下一个数字索引的位置
- Bucket *pInternalPointer; // 当前遍历的指针(foreach比for快的原因之一)
- Bucket *pListHead; // 存储数组头元素指针
- Bucket *pListTail; // 存储数组尾元素指针
- Bucket **arBuckets; // 存储hash数组
- dtor_func_t pDestructor; // 在删除元素时执行的回调函数,用于资源的释放
- zend_bool persistent; //指出了Bucket内存分配的方式。如果persisient为TRUE,则使用操作系统本身的内存分配函数为Bucket分配内存,否则使用PHP的内存分配函数。
- unsigned char nApplyCount; // 标记当前hash Bucket被递归访问的次数(防止多次递归)
- zend_bool bApplyProtection;// 标记当前hash桶允许不允许多次访问,不允许时,最多只能递归3次
- #if ZEND_DEBUG
- int inconsistent;
- #endif
- } HashTable;
然后 bucket 则如果有 hash 冲突,使得其相互之间是一个双向链表的结构
- typedef struct bucket {
- ulong h; // 对char *key进行hash后的值,或者是用户指定的数字索引值
- uint nKeyLength; // hash关键字的长度,如果数组索引为数字,此值为0
- void *pData; // 指向value,一般是用户数据的副本,如果是指针数据,则指向pDataPtr
- void *pDataPtr; //如果是指针数据,此值会指向真正的value,同时上面pData会指向此值
- struct bucket *pListNext; // 整个hash表的下一元素
- struct bucket *pListLast; // 整个哈希表该元素的上一个元素
- struct bucket *pNext; // 存放在同一个hash Bucket内的下一个元素
- struct bucket *pLast; // 同一个哈希bucket的上一个元素
- // 保存当前值所对于的key字符串,这个字段只能定义在最后,实现变长结构体
- char arKey[1];
- } Bucket;
PHP 内部的 hashtable 的示意图(来源于网络):
PHP5.3 里面数组的的实现方式的更多相关文章
- JavaScript中清空数组的三种方式
方式1,splice ? 1 2 3 var ary = [1,2,3,4]; ary.splice(0,ary.length); console.log(ary); // 输出 [],空数组,即被清 ...
- jquery取对象数组元素的错误方式
代码如下: <div id="div1"> <span>a</span> <span>b</span> <span ...
- java8 遍历数组的几种方式
java8 遍历数组的几种方式 2017年04月05日 09:15:46 阅读数:4640 风格色 2017-02-11 18:41 有如下一个String数组 String[] array = {& ...
- Java Array数组 遍历 四种方式(包含 Lambda 表达式遍历)
示例代码如下: package com.miracle.luna.lambda; import java.util.Arrays; /** * @Author Miracle Luna * @Date ...
- 五分钟学Java:打印Java数组最优雅的方式是什么?
在逛 Stack Overflow 的时候,发现了一些访问量像安第斯山一样高的问题,比如说这个:打印 Java 数组最优雅的方式是什么?访问量足足有 220W+,想不到啊,这么简单的问题竟然有这么多 ...
- C#初始化数组的三种方式
C#声明数组并初始化,有三种方式. 对于一维数组: using System;using System.Data;using System.Configuration;using System.Web ...
- 如何随机排序数组?使用多种方式!递归,迭代,洗牌,sort方法!
方式1: 使用sort 方法 ---- // 方法1 使用sort 方法 var arr = [1,2,3,4,5,6,7,8]; function foo(arr) { var cloneArr = ...
- 【Java】数组转List常见方式的对比
一.最常用通过 Arrays.asList(strArray) 方式,将数组转换List后,不能对List增删,只能查改,否则抛异常. 关键代码: List list = Arrays.asList( ...
- VBA遍历数组的2种方式
1.情景展示 VBA编程,如何对数组进行遍历? 2.解决方案 方式一:使用for循环 Sub 遍历数组1() '声明一个变量 Dim Arr As Variant '声明一个数字变量 Dim i ...
随机推荐
- Mac下Android配置及unity3d的导出Android
昨晚实在弄的太晚了,费尽脑汁才弄出来. ok,关于mac下的eclipse的安卓配置,我仅仅贴一个网址,就ok了 http://developer.android.com/sdk/index.html ...
- Pki原则
核心提示: 公开密钥和公开密钥证明书,产生的私钥client要么server证书.加密的公共密钥才能解密私钥文件只.私钥只能解密公开的加密文件.公众认为,它是开放的.所有的人都能够得到它.私人还表明, ...
- ASP.NET MVC局部视图
使用ASP.NET MVC局部视图避免JS拼接HTML,编写易于维护的HTML页面 以前使用ASP.NET WebForm开发时,喜欢使用Repeater控件嵌套的方式开发前台页面,这样就不用JS ...
- 疯狂html5演讲(两):HTML5简经常使用的元素和属性(一个):html5保留经常使用的元素
html5取出一小部分的元素和属性:主要删除的各种元素和属性与文档相关的风格.例<font>.width等待,html5建议规范css样式表来控制html文档样式. 1.基本元素 < ...
- [android] 百度地图开发 (两).所在地的城市定位和城市POI搜索
一个. 百度地图城市位置和POI搜索知识 上一篇文章"百度地图开发(一)"中讲述了怎样申请百度APIKey及解决显示空白网格的问题.该篇文章主要讲述怎样定位城市位置.定 ...
- JMM介绍
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHVvemhhbmZlbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- Nexus入门指南(图文)
Nexus入门指南(图文) 博客分类: Maven JavamavenGoogleApacheTomcat Nexus介绍 Nexus 是Maven仓库管理器,如果你使用Maven,你可以从Maven ...
- 基于Jquery 简单实用的弹出提示框
基于Jquery 简单实用的弹出提示框 引言: 原生的 alert 样子看起来很粗暴,网上也有一大堆相关的插件,但是基本上都是大而全,仅仅几句话可以实现的东西,可能要引入好几十k的文件,所以话了点时间 ...
- python包
有个伟人说过: python的学习很大一部分取决与你对第三方包的熟悉和掌握程度! virtualenv virtualenv用于创建独立的Python环境,多个Python相互独立,互不影响,它能够: ...
- Java编程思想笔记(第二章)
第二章 一切都是对象 尽管Java是基于C++的,但相比之下,Java是一种更纯粹的面向对象程序设计语言. c++和Java都是杂合型语言(hybird language) 用引用(referenc ...