搜索
首页后端开发php教程PHP内核研究:HASH表和变量_PHP教程
PHP内核研究:HASH表和变量_PHP教程Jul 14, 2016 am 10:08 AM
hashphp内核变量属性常量数据研究

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内部的内存管理机制分配并处理内存。
 
 

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/477783.htmlTechArticlePHP HASH表 在PHP中,所有的数据 无论变量,常量,类,属性 都用Hash表来实现. 先要说说 HASH表 typedef struct bucket { ulong h; /* Used for numeric indexing */ ui...
声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
php怎么把负数转为正整数php怎么把负数转为正整数Apr 19, 2022 pm 08:59 PM

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

php怎么实现几秒后执行一个函数php怎么实现几秒后执行一个函数Apr 24, 2022 pm 01:12 PM

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php怎么除以100保留两位小数php怎么除以100保留两位小数Apr 22, 2022 pm 06:23 PM

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

php怎么根据年月日判断是一年的第几天php怎么根据年月日判断是一年的第几天Apr 22, 2022 pm 05:02 PM

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php字符串有没有下标php字符串有没有下标Apr 24, 2022 am 11:49 AM

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

php怎么判断有没有小数点php怎么判断有没有小数点Apr 20, 2022 pm 08:12 PM

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

php怎么替换nbsp空格符php怎么替换nbsp空格符Apr 24, 2022 pm 02:55 PM

方法:1、用“str_replace(" ","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\&nbsp\;||\xc2\xa0)/","其他字符",$str)”语句。

php怎么读取字符串后几个字符php怎么读取字符串后几个字符Apr 22, 2022 pm 08:31 PM

在php中,可以使用substr()函数来读取字符串后几个字符,只需要将该函数的第二个参数设置为负值,第三个参数省略即可;语法为“substr(字符串,-n)”,表示读取从字符串结尾处向前数第n个字符开始,直到字符串结尾的全部字符。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
1 个月前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

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