首页 php教程 php手册 PHP内核研究:HASH表和变量

PHP内核研究:HASH表和变量

Jun 13, 2016 am 10:54 AM
hash php 内核 变量 属性 常量 数据 研究

PHP HASH表

 

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

 

先要说说 HASH表

 

 

 

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; 

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

 

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 nTableSize = 1

 } 

//为了提高计算效率,系统自动会将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; 

 

    在读源码的时候 ,经常会看到 EG,PG,CG这样的宏

CG是 compile_global的简写

 

EG是excutor_global的简写

 

G就是全局变量的意思

 

我们就以EG宏为例

 

 

 

#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 

 

 

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

 

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

 

在/Zend/zend.h里面定义

 

typedef struct _zend_executor_globals zend_executor_globals;

 

是一个 _zend_executor_globals的别名

 

同一个文件里找到它

 

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

 

 

 

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]; 

}; 

 

 

 

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

 

PHP里最基本的单元 变量:

在PHP里 定义一个变量 再简单不过了

$a=1; 

?> 

 

但是在内核中 它是用一个 zval结构体实现的

如上面定义变量 在内核中则执行了下面这些代码

 

 

 

zval *val; 

MAKE_STD_ZVAL(val);  //申请一块内存 

ZVAL_STRING(val,"hello",1);//用ZVAL_STRING设置它的值为 "hello" 

ZEND_SET_SYMBOL(EG(active_symbol_table),"a",val));//将  val指针加入到符号表里面去 

宏 MAKE_STD_ZVAL 定义如下

 

 

 

#define MAKE_STD_ZVAL(zv)                                \ 

ALLOC_ZVAL(zv); \  //它归根到底等于 (p) = (type *) emalloc(sizeof(type)) 

INIT_PZVAL(zv); 

INIT_PZVAL定义在

 

 

 

#define INIT_PZVAL(z)           \ 看得出它是初始化参数 

(z)->refcount__gc = 1;  \ 

(z)->is_ref__gc = 0; 

那么 zval到底是什么呢

在zend/zend.h里面

typedef struct _zval_struct zval; //原来它是 _zval_struct 的别名

_zval_struct 定义如下

 

 

 

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来创建一个PHP变量

这里需要一个扩展,PHP如果用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); 

第三行和第四行的作用 与MAKE_STD_ZVAL的作用相同,给value分配内存空间

第5-9行 的作用与ZVAL_STRING的作用相同,

最后一行 是将value创建一个 在PHP里叫$a的变量..并添加到局部Hash表里..

这样 在PHP里

 

 

 

test_siren(1); 

echo $a; 

?> 

就会输出 “create a php variable”

OK,

大功告成

注意,我是为了让大家看到PHP内部创建变量的流程 才采用C的形式创建变量,

绝对不推荐大家这样做.

还是一定要用PHP内部的内存管理机制分配并处理内存。

 

 

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

<🎜>:泡泡胶模拟器无穷大 - 如何获取和使用皇家钥匙
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系统,解释
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆树的耳语 - 如何解锁抓钩
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1675
14
CakePHP 教程
1429
52
Laravel 教程
1333
25
PHP教程
1278
29
C# 教程
1257
24
PHP与Python:了解差异 PHP与Python:了解差异 Apr 11, 2025 am 12:15 AM

PHP和Python各有优势,选择应基于项目需求。1.PHP适合web开发,语法简单,执行效率高。2.Python适用于数据科学和机器学习,语法简洁,库丰富。

PHP:网络开发的关键语言 PHP:网络开发的关键语言 Apr 13, 2025 am 12:08 AM

PHP是一种广泛应用于服务器端的脚本语言,特别适合web开发。1.PHP可以嵌入HTML,处理HTTP请求和响应,支持多种数据库。2.PHP用于生成动态网页内容,处理表单数据,访问数据库等,具有强大的社区支持和开源资源。3.PHP是解释型语言,执行过程包括词法分析、语法分析、编译和执行。4.PHP可以与MySQL结合用于用户注册系统等高级应用。5.调试PHP时,可使用error_reporting()和var_dump()等函数。6.优化PHP代码可通过缓存机制、优化数据库查询和使用内置函数。7

PHP和Python:比较两种流行的编程语言 PHP和Python:比较两种流行的编程语言 Apr 14, 2025 am 12:13 AM

PHP和Python各有优势,选择依据项目需求。1.PHP适合web开发,尤其快速开发和维护网站。2.Python适用于数据科学、机器学习和人工智能,语法简洁,适合初学者。

PHP行动:现实世界中的示例和应用程序 PHP行动:现实世界中的示例和应用程序 Apr 14, 2025 am 12:19 AM

PHP在电子商务、内容管理系统和API开发中广泛应用。1)电子商务:用于购物车功能和支付处理。2)内容管理系统:用于动态内容生成和用户管理。3)API开发:用于RESTfulAPI开发和API安全性。通过性能优化和最佳实践,PHP应用的效率和可维护性得以提升。

PHP的持久相关性:它还活着吗? PHP的持久相关性:它还活着吗? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在现代编程领域中依然占据重要地位。1)PHP的简单易学和强大社区支持使其在Web开发中广泛应用;2)其灵活性和稳定性使其在处理Web表单、数据库操作和文件处理等方面表现出色;3)PHP不断进化和优化,适用于初学者和经验丰富的开发者。

PHP和Python:解释了不同的范例 PHP和Python:解释了不同的范例 Apr 18, 2025 am 12:26 AM

PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

PHP和Python:代码示例和比较 PHP和Python:代码示例和比较 Apr 15, 2025 am 12:07 AM

PHP和Python各有优劣,选择取决于项目需求和个人偏好。1.PHP适合快速开发和维护大型Web应用。2.Python在数据科学和机器学习领域占据主导地位。

PHP与其他语言:比较 PHP与其他语言:比较 Apr 13, 2025 am 12:19 AM

PHP适合web开发,特别是在快速开发和处理动态内容方面表现出色,但不擅长数据科学和企业级应用。与Python相比,PHP在web开发中更具优势,但在数据科学领域不如Python;与Java相比,PHP在企业级应用中表现较差,但在web开发中更灵活;与JavaScript相比,PHP在后端开发中更简洁,但在前端开发中不如JavaScript。

See all articles