PHP源码分析-变量
1. 变量的三要素
变量名称,变量类型,变量值
那么在PHP用户态下变量类型都有哪些,如下:
// Zend/zend.h
#define IS_NULL 0
#define IS_LONG 1
#define IS_DOUBLE 2
#define IS_BOOL 3
#define IS_ARRAY 4
#define IS_OBJECT 5
#define IS_STRING 6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_AST 9
#define IS_CALLABLE 10
2. 变量值和变量类型的存储
变量的类型和值被存储在结构体zval中,如下:
/ Zend/zend_types.h
typedef struct _zval_struct zval; // Zend/zend.h
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;
zend_ast *ast;
} zvalue_value; struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount__gc;
zend_uchar type; /* active type */
zend_uchar is_ref__gc;
};
先看结构体_zval_struct,它的成员中value存储变量的值,type存储变量的类型,refcount__gc和is_ref__gc是变量引用相关的标记,先忽略;
而具体存储变量值的结构体_zvalue_value如何存储一个变量的值呢?根据变量的类型进行不同方式的存储,如下:
a. 变量类型为boolean(ZVAL_BOOL), integer(ZVAL_LONG), resource(ZVAL_RESOURCE)
zval中的type存储变量类型(IS_BOOL, IS_LONG, IS_RESOURCE),zvalue_value中的lval存储变量值
b. 变量类型为float(ZVAL_DOUBLE)
zval中的type存储变量类型(IS_DOUBLE),zvalue_value中的dval存储变量值
c. 变量类型为null(ZVAL_NULL)
zval中的type存储变量类型(IS_NULL),不需要存储值
d. 变量类型为字符串
zval中的type存储变量类型(IS_STRING),zvalue_value中的结构体str存储字符串值和字符串长度
e. 变量类型为数组
zval中的type存储变量类型(IS_ARRAY),zvalue_value中的*ht将指向一个哈希表,而这个哈希表里则存储数组的值
f. 变量类型为对象
zval中的type存储变量类型(IS_OBJECT),zvalue_value中的obj用于存储其值
以上对于变量类型为数组时,数组值是使用内核态的哈希表存储的,那么PHP内核态的哈希表到底是个什么东东?
3. PHP内核态的哈希表
/ Zend/zend_hash.h
typedef struct bucket {
ulong h; /* Used for numeric indexing */
uint nKeyLength;
void *pData;
void *pDataPtr;
struct bucket *pListNext;
struct bucket *pListLast;
struct bucket *pNext;
struct bucket *pLast;
const char *arKey;
} Bucket; typedef struct _hashtable {
uint nTableSize;
uint nTableMask;
uint nNumOfElements;
ulong nNextFreeElement;
Bucket *pInternalPointer; /* Used for element traversal */
Bucket *pListHead;
Bucket *pListTail;
Bucket **arBuckets;
dtor_func_t pDestructor;
zend_bool persistent;
unsigned char nApplyCount;
zend_bool bApplyProtection;
#if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;
首先在理解哈希表时,先不要想它和PHP数组,变量符号表等的关系。先集中精神理解哈希表本身。上面代码里的HashTable和bucket实际上是为了表示多个有关联的元素,
其中一个bucket代表一个元素,它的*pListNext和*pListLast分别指向它的下一个和上一个bucket元素,所以这些bucket实际上是一个双向链表。而bucket元素具体的值存放在了由*pData指向的一块内存中,元素名称在保存在*arKey中;
HashTable中的*pListHead和*pListTail分别指向bucket元素构成的双向链表的头和尾,arBuckets则是一个数组,数组的key是一个哈希值(bucket元素名称的hash值),数组的value是双向链表中一个bucket元素的地址指针,arBuckets保存了所有的双向链表中元素的地址指针。
因为有了arBuckets,便能够快速的根据一个元素的名称检索到对应的bucket元素。
以上为PHP内核态哈希表的简单介绍,也是核心功能介绍。
4. 用户态的数组在内核态由哈希表存储
一个数组是由多个key->value的元素构成,而哈希表正可以表示这个元素构成。比如,要想一个数组push一个元素,PHP内核先为此数组元素申请一块bucket内存,将数组元素的key进行哈希计算后得到一个哈希值,再操作HashTable中的*pListHead,和Bucket中的pListNext,pListLast。
5. 哈希表是PHP内核的核心
哈希表作用巨大,比如:
a. 数组由哈希表实现
b. 用户态的php脚本里出现的所有全局变量和所有局部变量在内核态也是使用哈希表来组织到一起
当内核检索某个变量时,通过对变量名的哈希值到哈希表的arBuckets去找到对应的Bucket。
//Zend/zend_globals.h struct _zend_executor_globals {
... HashTable *active_symbol_table;
HashTable symbol_table; /* main symbol table */ ...
}
active_symbol_table指向当前局部变量的哈希表;而symbol_table则是全局变量的哈希表
PHP源码分析-变量的更多相关文章
- HashTable原理与源码分析
本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作,如有错误之处忘不吝批评指正! HashTable内部存储结构 HashTable内部存储结构为数组+单向链 ...
- Set存储元素为啥是唯一的(以HashSet为例源码分析)
本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作,如有错误之处忘不吝批评指正! 说些废话 以前面试的时候会遇到有人问Set 和list的区别 这个很好答,但 ...
- Spark大师之路:广播变量(Broadcast)源码分析
概述 最近工作上忙死了……广播变量这一块其实早就看过了,一直没有贴出来. 本文基于Spark 1.0源码分析,主要探讨广播变量的初始化.创建.读取以及清除. 类关系 BroadcastManager类 ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- ABP源码分析十:Unit Of Work
ABP以AOP的方式实现UnitOfWork功能.通过UnitOfWorkRegistrar将UnitOfWorkInterceptor在某个类被注册到IOCContainner的时候,一并添加到该类 ...
- ABP源码分析二十七:ABP.Entity Framework
IRepository:接口定义了Repository常见的方法 AbpRepositoryBase:实现了IRepository接口的常见方法 EfRepositoryBase:实现了AbpRepo ...
- u-boot源码分析之C语言段
题外话: 最近一直在学习u-boot的源代码,从代码量到代码风格,都让我认识到什么才是真正的程序.以往我所学到的C语言知识和u-boot的源代码相比,实在不值一提.说到底,机器都是0和1控制的.感觉这 ...
- LinqToDB 源码分析——生成表达式树
当我们知道了Linq查询要用到的数据库信息之后.接下就是生成对应的表达式树.在前面的章节里面笔者就已经介绍过.生成表达式树是事实离不开IQueryable<T>接口.而处理表达式树离不开I ...
- MyCat源码分析系列之——结果合并
更多MyCat源码分析,请戳MyCat源码分析系列 结果合并 在SQL下发流程和前后端验证流程中介绍过,通过用户验证的后端连接绑定的NIOHandler是MySQLConnectionHandler实 ...
随机推荐
- 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成
阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用[3]--体验
运行环境,客户端一般编译为.Net 3.5 Unity兼容,服务端因为用了一些库,所以一般为4.0 或往上.同一份代码,建立拥有2个项目.客户端引用: WindNet.Client服务端引用: OpL ...
- jq跑马灯效果
这几天公司产品有个无缝循环滚动的广告跑马灯要做,最开始想到的是<marquee>标签,但在PC端正常,在安卓广告屏上却怎么都跑不动,后来用的css3的animation,结果也是PC端及其 ...
- Android Ormlite 学习笔记2 -- 主外键关系
以上一篇为例子,进行主外键的查询 定义Users.java 和 Role.java Users -- Role 关系为:1对1 即父表关系 Role -- Users 关系为:1对多 即子表关系 下面 ...
- Hawk 6. 高级话题:子流程系统
子流程的定义 当流程设计的越来越复杂,越来越长时,就难以进行管理了.因此,采用模块化的设计才会更加合理.本节我们介绍子流程的原理和使用. 所谓子流程,就是能先构造出一个流程,然后被其他流程调用.被调用 ...
- [.NET] C# 知识回顾 - 委托 delegate (续)
C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...
- 读python源码--对象模型
学python的人都知道,python中一切皆是对象,如class生成的对象是对象,class本身也是对象,int是对象,str是对象,dict是对象....所以,我很好奇,python是怎样实现这些 ...
- 代码的坏味道(17)——夸夸其谈未来性(Speculative Generality)
坏味道--夸夸其谈未来性(Speculative Generality) 特征 存在未被使用的类.函数.字段或参数. 问题原因 有时,代码仅仅为了支持未来的特性而产生,然而却一直未实现.结果,代码变得 ...
- log4net使用手册
1. log4net简介 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.Java平台下,它还 ...
- Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
学习架构探险,从零开始写Java Web框架时,在学习到springAOP时遇到一个异常: "C:\Program Files\Java\jdk1.7.0_40\bin\java" ...