原创:PHP内核研究:HASH表和变量

PHP HASH表

在PHP中,所有的数据 无论变量,常量,类,属性 都用Hash表来实现.

先要说说 HASH表

[c]
typedef struct bucket {
ulong h; /* Used for numeric indexing */
uint nKeyLength; //key长度
void *pData; //指向 Bucke保存的数据 指针
void *pDataPtr; //指针数据
struct bucket *pListNext; //下一个元素指针
struct bucket *pListLast;//上一个元素指针
struct bucket *pNext;
struct bucket *pLast;
char arKey[1]; /* Must be last element */
} Bucket;
typedef struct _hashtable {
uint nTableSize;//HashTable的大小
uint nTableMask;//等于nTableSize-1
uint nNumOfElements;//对象个数
ulong nNextFreeElement;//指向下一个空元素位置 nTableSize+1
Bucket *pInternalPointer; /* Used for element traversal *///保存当前遍历的指针
Bucket *pListHead;//头元素指针
Bucket *pListTail;//尾元素指针
Bucket **arBuckets;//存储hash数组数据
dtor_func_t pDestructor;//类似于析构函数
zend_bool persistent;//用哪种方法分配内存空间 PHP统一管理内存还是用普通的malloc
unsigned char nApplyCount;//当前hash bucket被访问的次数,是否遍历过数据,防止无限递归循环
zend_bool bApplyProtection;
#if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;
[/c]



我们结合 HASH表初始化函数来说

[c]
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;
Bucket **tmp;

SET_INCONSISTENT(HT_OK);

if (nSize >= 0x80000000) { //HASH表大小大于0x8则初始化为0x8
/* prevent overflow */
ht->nTableSize = 0x80000000;
} else {
while ((1U << i) < nSize) { //调整为 2的n次方 i++; } ht->nTableSize = 1 << i;//HASH bucket大小 为 2的i次方 i=3 ,nTableSize最小值为8
}
//为了提高计算效率,系统自动会将nTableSize调整到最小一个不小于nTableSize的2的整数次方。也就是说,如果在初始化HashTable时指定一个nTableSize不是2的整数次方,系统将会自动调整nTableSize的值

ht->nTableMask = ht->nTableSize - 1;
ht->pDestructor = pDestructor;//一个函数指针,当HashTable发生增,删,改时调用
ht->arBuckets = NULL;
ht->pListHead = NULL;
ht->pListTail = NULL;
ht->nNumOfElements = 0;
ht->nNextFreeElement = 0;
ht->pInternalPointer = NULL;
ht->persistent = persistent;//如果persisient为TRUE,则使用操作系统本身的内存分配函数为Bucket分配内存,否则使用PHP的内存分配函数
ht->nApplyCount = 0;
ht->bApplyProtection = 1;

/* Uses ecalloc() so that Bucket* == NULL */
if (persistent) { //操作系统本身内存分配方式分配内存,calloc分配内存后自动初始化为0
tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *));
if (!tmp) {
return FAILURE;
}
ht->arBuckets = tmp;
} else {//用PHP的内存管理机制分配内存
tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *));
if (tmp) {
ht->arBuckets = tmp;
}
}
//自动申请一块内存给arBuckets,该内存大小等于 nTableSize
return SUCCESS;
}

[/c]
  • 在读源码的时候 ,经常会看到 EG,PG,CG这样的宏

CG是 compile_global的简写

EG是excutor_global的简写

G就是全局变量的意思

我们就以EG宏为例:

[c]
#ifdef ZTS
# define EG(v) TSRMG(executor_globals_id, zend_executor_globals *, v)
#else
# define EG(v) (executor_globals.v)
extern ZEND_API zend_executor_globals executor_globals;
#endif
[/c]

很简单 只是一个获取全局变量的宏

那么我们看看 zend_executor_globals这个结构体

在/Zend/zend.h里面定义

typedef struct _zend_executor_globals zend_executor_globals;

是一个 _zend_executor_globals的别名

同一个文件里找到它

PHP的所有 局部变量,全局变量,函数,类的 Hash表 都在这里定义了

[c]
struct _zend_executor_globals {
zval **return_value_ptr_ptr;

zval uninitialized_zval;
zval *uninitialized_zval_ptr;

zval error_zval;
zval *error_zval_ptr;

zend_ptr_stack arg_types_stack;

/* symbol table cache */
HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
HashTable **symtable_cache_limit;
HashTable **symtable_cache_ptr;

zend_op **opline_ptr;

HashTable *active_symbol_table; //局部变量
HashTable symbol_table; /* main symbol table */ //全局变量

HashTable included_files; /* files already included */ //include的文件

JMP_BUF *bailout;

int error_reporting;
int orig_error_reporting;
int exit_status;

zend_op_array *active_op_array;

HashTable *function_table; /* function symbol table */ //函数表
HashTable *class_table; /* class table */ //类表
HashTable *zend_constants; /* constants table */ //常量表

zend_class_entry *scope;
zend_class_entry *called_scope; /* Scope of the calling class */

zval *This;

long precision;

int ticks_count;

zend_bool in_execution;
HashTable *in_autoload;
zend_function *autoload_func;
zend_bool full_tables_cleanup;

/* for extended information support */
zend_bool no_extensions;

#ifdef ZEND_WIN32
zend_bool timed_out;
OSVERSIONINFOEX windows_version_info;
#endif

HashTable regular_list;
HashTable persistent_list;

zend_vm_stack argument_stack;

int user_error_handler_error_reporting;
zval *user_error_handler;
zval *user_exception_handler;
zend_stack user_error_handlers_error_reporting;
zend_ptr_stack user_error_handlers;
zend_ptr_stack user_exception_handlers;

zend_error_handling_t error_handling;
zend_class_entry *exception_class;

/* timeout support */
int timeout_seconds;

int lambda_count;

HashTable *ini_directives;
HashTable *modified_ini_directives;

zend_objects_store objects_store;
zval *exception, *prev_exception;
zend_op *opline_before_exception;
zend_op exception_op[3];

struct _zend_execute_data *current_execute_data;

struct _zend_module_entry *current_module;

zend_property_info std_property_info;

zend_bool active;

void *saved_fpu_cw;

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
[/c]


这里先简单看看,以后用到的时候再细说,

  • PHP里最基本的单元 变量:
    在PHP里 定义一个变量 再简单不过了
[php]

[/php]

但是在内核中 它是用一个 zval结构体实现的
如上面定义变量 在内核中则执行了下面这些代码

[c]
zval *val;
MAKE_STD_ZVAL(val); //申请一块内存
ZVAL_STRING(val,"hello",1);//用ZVAL_STRING设置它的值为 "hello"
ZEND_SET_SYMBOL(EG(active_symbol_table),"a",val));//将 val指针加入到符号表里面去
[/c]

宏 MAKE_STD_ZVAL 定义如下

[c]
#define MAKE_STD_ZVAL(zv) \
ALLOC_ZVAL(zv); \ //它归根到底等于 (p) = (type *) emalloc(sizeof(type))
INIT_PZVAL(zv);
[/c]

INIT_PZVAL定义在

[c]
#define INIT_PZVAL(z) \ 看得出它是初始化参数
(z)->refcount__gc = 1; \
(z)->is_ref__gc = 0;
[/c]

那么 zval到底是什么呢
在zend/zend.h里面
typedef struct _zval_struct zval; //原来它是 _zval_struct 的别名
_zval_struct 定义如下

[c]
typedef union _zvalue_value {
long lval; //保存long类型的数据
double dval; //保存 double类型的数据
struct {
char *val; //真正的值在这里
int len; //这里返回长度
} str;
HashTable *ht;
zend_object_value obj; //这是一个对象
} zvalue_value;

struct _zval_struct {
zvalue_value value; //保存的值
zend_uint refcount__gc;//被引用的次数 如果为1 则只被自己使用如果大于1 则被其他变量以&的形式引用.
zend_uchar type; //数据类型 这也是 为什么 PHP是弱类型的原因
zend_uchar is_ref__gc; //表示是否为引用
};
[/c]

如果还是不够清楚..那么我们实战一下..用C来创建一个PHP变量
这里需要一个扩展,PHP如果用C扩展模块 这里就不说了
关键代码

[c]
PHP_FUNCTION(test_siren){
zval *value;
char *s="create a php variable";
value=(zval*)malloc(sizeof(zval));
memset(value,0,sizeof(value));
value->is_ref__gc=0; //非引用变量
value->refcount__gc=1;//引用次数 只有自己
value->type=IS_STRING;//类型为字符串
value->value.str.val=s;//值
value->value.str.len=strlen(s);//长度
ZEND_SET_SYMBOL(EG(active_symbol_table),"a",value);
}
[/c]

第三行和第四行的作用 与MAKE_STD_ZVAL的作用相同,给value分配内存空间
第5-9行 的作用与ZVAL_STRING的作用相同,
最后一行 是将value创建一个 在PHP里叫$a的变量..并添加到局部Hash表里..
这样 在PHP里

[php]

[/php]

就会输出 "create a php variable"
OK,
大功告成
注意,我是为了让大家看到PHP内部创建变量的流程 才采用C的形式创建变量,
绝对不推荐大家这样做.
还是一定要用PHP内部的内存管理机制分配并处理内存,\.


转载于:https://www.cnblogs.com/si-ren/archive/2012/03/10/2447628.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/297302.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 11 小技巧- 安装

Windows 11 依赖于TPM 2.0&#xff0c;什么是TPM呢?TPM技术旨在提供基于硬件的与安全性相关的功能。TPM芯片是⼀个安全的加密处理器&#xff0c;有助于执⾏⽣成、存储和限制加密密钥的使用等操作。TPM芯片包含多重物理安全机制&#xff0c;具有防篡改功能&#xff0c;恶意软件…

如何判断一个人是不是值得深入交流?

全世界只有3.14 % 的人关注了爆炸吧知识每次翻看刚加好友的朋友圈时&#xff0c;都会对 ta 产生直观的判断。如果朋友圈很丰富&#xff0c;往往会觉得 ta 很有趣&#xff0c;会迫切想要和 ta 链接&#xff0c;而看到某些很单调的朋友圈&#xff0c;根本就没有深入沟通的欲望。真…

Restive.js – 轻松让网站变成响应式和自适应

Restive.js 是一个 jQuery 插件&#xff0c;可以帮助您轻松快捷地添加响应式功能到你网站&#xff0c;适应几乎所有拥有 Web 功能的设备。使用设备检测&#xff0c;高级管理断点&#xff0c;以及方向管理的组合&#xff0c;Restive.js 会给你的网站提供一种不可思议的能力。 在…

消息分发的同步均衡策略

2019独角兽企业重金招聘Python工程师标准>>> TimeTunnel在做消息分发时有这样一个场景: A类消息需要做实时分析, 且量很大, 故它的消费者不会只是一台机器, 而是一组机器, 并要求这组中每台机器收到的消息量应该平均的, 即A消息在某个时刻有100条, 若有4台机器消费…

ssh长时间不操作便断开_连接SSH长时间不操作断开解决办法

经常连接ssh长时间不操作就断开&#xff0c;实在忍无可忍&#xff0c;每次都想解决这个问题&#xff0c;但是就是懒得搞&#xff0c;这次必须得一刀解决。解决方法一&#xff1a;服务器配置1、 连接SSHssh root192.168.0.1复制代码2、编辑sshd_configvim /etc/ssh/sshd_config复…

当下流行的直播技术demo演示

nginx-http-flv-module&#xff08;更新不是很频繁&#xff09; SRS: https://ossrs.net/lts/zh-cn/&#xff08;独立官网&#xff0c;目前最新稳定版version5&#xff09; 基于SRS搭建直播demo演示&#xff1a; 一、搭建流媒体服务器 参见官网&#xff1a;https://ossrs.ne…

SQL复制表

View Code --创建test_employee_info临时表结构&#xff0c;不保留关联关系select * into test_employee_info from employee_info where 1<>1;declare num intset num1while num<6begininsert into test_employee_info select employee_codepcast(num as varchar(1)…

Workflow Core + asp.net core 5.0 实现简单审批工作流

我们知道企业业务系统到处都可以审批工作流的&#xff0c;但也很少有像OA系统一样复杂多级多条件的审批工作流需要设计&#xff0c;所以我们需要一个轻量级的容易上手的workflow框架&#xff0c;通过GitHub,我发现danielgerlag/workflow-core 就非常合适&#xff0c;我下面我通…

超1亿人选择朋友圈三天可见,背后的原因值得深思

全世界只有3.14 % 的人关注了爆炸吧知识每次翻看刚加好友的朋友圈时&#xff0c;都会对 ta 产生直观的判断。如果朋友圈很丰富&#xff0c;往往会觉得 ta 很有趣&#xff0c;会迫切想要和 ta 链接&#xff0c;而看到某些很单调的朋友圈&#xff0c;根本就没有深入沟通的欲望。真…

基于HTML5手机上下滑动翻页特效

基于HTML5手机上下滑动翻页特效。这是一款手机移动端触屏滑动翻页代码下载。效果图如下&#xff1a; 在线预览 源码下载 实现的代码。 html代码&#xff1a; <section class"u-alert"><img style"display:none;" src"images/loading_larg…

一寸照纯红色底图片_和记场下载

新能的事普及棘手源汽依然情车的是件&#xff0c;为王花燃油但和比车相&#xff0c;为王花底解电池和记场下载在没决续基础建设高额问题航、有彻以及前充电成本&#xff0c;它的体量不大依旧&#xff0c;新能形成正在逐渐之势推广尽管局部源汽全球车的所以。第一直接兼老个家话…

学点css基础

中午时间学点css&#xff0c;附带http://www.w3cschool.cc/css/css-tutorial.html这个链接&#xff01; 中午的时间学了这些东西&#xff01;如下图: 附带代码&#xff1a; 1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset&quo…

套套原来是这样装袋的,40个机械动图看懂好像并不容易。。。

今天咱们来多方位的展示机械的魅力1、真在的柔性自动包装线&#xff0c;可以同时实现一条线上多种不同物体的包装&#xff1a;好强大&#xff0c;美中不足的是没有防震包装&#xff0c;容易压坏商品。另外从视频上可以看出来纸板和物品一块出来&#xff0c;纸板出来时已经裁剪好…

云原生开发框架dapr环境搭建:CLI安装和初始化

dapr 是微软的一个云原生&#xff08;Cloud Native&#xff09;开源项目&#xff0c;英文全称&#xff1a;Distributed Application Runtime&#xff0c;中文要翻译的话就是&#xff1a;分布式应用运行时。也就是一个运行时框架&#xff0c;面向云原生架构。dapr官网地址&#…

java map 值排序_使用Java8 Stream API对Map类型按照键或值进行排序

在这篇文章中&#xff0c;您将学习如何使用Java对Map按照键或值进行排序。前几日有位朋友面试遇到了这个问题&#xff0c;看似很简单的问题&#xff0c;但是如果不仔细研究一下也是很容易让人懵圈的面试题。所以我决定写这样一篇文章。在Java中&#xff0c;有多种方法可以对Map…

沙漠上不小心挖了个洞,让这个地狱之门般的巨坑,燃烧了50年

全世界只有3.14 % 的人关注了爆炸吧知识在土库曼斯坦的卡拉库姆沙漠深处&#xff0c;有一个神奇的巨坑&#xff0c;直径约为70米&#xff0c;它无论白天还是黑夜&#xff0c;永远都在燃烧。这个坑的周围一片荒芜&#xff0c;坑里也没有任何明显在助燃的东西但坑内燃烧的大火近5…

不同用户同时并发测压_简单聊聊吞吐量(TPS)、QPS、并发数、响应时间(RT)概念...

1、 响应时间(RT) 响应时间是指系统对请求作出响应的时间。直观上看&#xff0c;这个指标与人对软件性能的主观感受是非常一致的&#xff0c;因为它完整地记录了整个计算机系统处理请求的时间。由于一个系统通常会提供许多功能&#xff0c;而不同功能的处理逻辑也千差万别&…

读《沟通的方法》

众所周知&#xff0c;沟通在工作和生活中是一项非常重要的技能&#xff0c;但很多人却用不好这项技能&#xff0c;最近中秋假期&#xff0c;看完了得到 CEO 脱不花写的《沟通的方法》&#xff0c;觉得很有收获。脱不花没有上过大学&#xff0c;能有今天的成就&#xff0c;超强的…

STP的初使化过程

STP初使化过程分为网桥角色(根网桥,非根网桥)的确定和端口角色(根端口&#xff0c;指定端口,阻塞端口)的确定&#xff0c;最终端口状态(稳定状态有blocking&#xff0c;forwarding)确定后&#xff0c;树就形成了。 STP端口状态的改变依赖于端口角色的改变和计时器的超时&#x…

收藏!这10部关于数学的顶级纪录片,告诉孩子数学跟枯燥不沾边!

全世界只有3.14 % 的人关注了爆炸吧知识学好数学&#xff0c;必须从娃娃抓起&#xff01;数学是人类的高级思维活动&#xff0c;越往顶层走&#xff0c;需要的各种思维能力就越多。所以&#xff0c;要想孩子数学好&#xff0c;首先要帮他“打牢思维的地基”。怎么打&#xff1f…