PHPHASH表在PHP中,所有的数据无论变量,常量,类,属性都用Hash表来实现。下面学步园小编来讲解下PHP内核HASH表是什么?
PHP内核HASH表是什么
typedefstructbucket{
ulongh;/*Usedfornumericindexing*/
uintnKeyLength;//key长度
void*pData;//指向Bucke保存的数据指针
void*pDataPtr;//指针数据
structbucket*pListNext;//下一个元素指针
structbucket*pListLast;//上一个元素指针
structbucket*pNext;
structbucket*pLast;
chararKey[1];/*Mustbelastelement*/
}Bucket;
typedefstruct_hashtable{
uintnTableSize;//HashTable的大小
uintnTableMask;//等于nTableSize-1
uintnNumOfElements;//对象个数
ulongnNextFreeElement;//指向下一个空元素位置nTableSize+1
Bucket*pInternalPointer;/*Usedforelementtraversal*///保存当前遍历的指针
Bucket*pListHead;//头元素指针
Bucket*pListTail;//尾元素指针
Bucket**arBuckets;//存储hash数组数据
dtor_func_tpDestructor;//类似于析构函数
zend_boolpersistent;//用哪种方法分配内存空间PHP统一管理内存还是用普通的malloc
unsignedcharnApplyCount;//当前hashbucket被访问的次数,是否遍历过数据,防止无限递归循环
zend_boolbApplyProtection;
#ifZEND_DEBUG
intinconsistent;
#endif
}HashTable;
我们结合HASH表初始化函数来说
ZEND_APIint_zend_hash_init(HashTable*ht,uintnSize,hash_func_tpHashFunction,dtor_func_tpDestructor,zend_boolpersistentZEND_FILE_LINE_DC)
{
uinti=3;
Bucket**tmp;
SET_INCONSISTENT(HT_OK);
if(nSize>=0x80000000){//HASH表大小大于0x8则初始化为0x8
/*preventoverflow*/
ht->nTableSize=0x80000000;
}else{
while((1U《i)nTableSize=1《i;//HASHbucket大小为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;
/*Usesecalloc()sothatBucket*==NULL*/
if(persistent){//操作系统本身内存分配方式分配内存,calloc分配内存后自动初始化为0
tmp=(Bucket**)calloc(ht->nTableSize,sizeof(Bucket*));
if(!tmp){
returnFAILURE;
}
ht->arBuckets=tmp;
}else{//用PHP的内存管理机制分配内存
tmp=(Bucket**)ecalloc_rel(ht->nTableSize,sizeof(Bucket*));
if(tmp){
ht->arBuckets=tmp;
}
}
//自动申请一块内存给arBuckets,该内存大小等于nTableSize
returnSUCCESS;
}
在读源码的时候,经常会看到EG,PG,CG这样的宏
CG是compile_global的简写
EG是excutor_global的简写
G就是全局变量的意思
我们就以EG宏为例
#ifdefZTS
#defineEG(v)TSRMG(executor_globals_id,zend_executor_globals*,v)
#else
#defineEG(v)(executor_globals.v)
externZEND_APIzend_executor_globalsexecutor_globals;
#endif
很简单只是一个获取全局变量的宏
那么我们看看zend_executor_globals这个结构体
在/Zend/zend.h里面定义
typedefstruct_zend_executor_globalszend_executor_globals;
是一个_zend_executor_globals的别名
同一个文件里找到它
PHP的所有局部变量,全局变量,函数,类的Hash表都在这里定义了
struct_zend_executor_globals{
zval**return_value_ptr_ptr;
zvaluninitialized_zval;
zval*uninitialized_zval_ptr;
zvalerror_zval;
zval*error_zval_ptr;
zend_ptr_stackarg_types_stack;
/*symboltablecache*/
HashTable*symtable_cache[SYMTABLE_CACHE_SIZE];
HashTable**symtable_cache_limit;
HashTable**symtable_cache_ptr;
zend_op**opline_ptr;
HashTable*active_symbol_table;//局部变量
HashTablesymbol_table;/*mainsymboltable*///全局变量
HashTableincluded_files;/*filesalreadyincluded*///include的文件
JMP_BUF*bailout;
interror_reporting;
intorig_error_reporting;
intexit_status;
zend_op_array*active_op_array;
HashTable*function_table;/*functionsymboltable*///函数表
HashTable*class_table;/*classtable*///类表
HashTable*zend_constants;/*constantstable*///常量表
zend_class_entry*scope;
zend_class_entry*called_scope;/*Scopeofthecallingclass*/
zval*This;
longprecision;
intticks_count;
zend_boolin_execution;
HashTable*in_autoload;
zend_function*autoload_func;
zend_boolfull_tables_cleanup;
/*forextendedinformationsupport*/
zend_boolno_extensions;
#ifdefZEND_WIN32
zend_booltimed_out;
OSVERSIONINFOEXwindows_version_info;
#endif
HashTableregular_list;
HashTablepersistent_list;
zend_vm_stackargument_stack;
intuser_error_handler_error_reporting;
zval*user_error_handler;
zval*user_exception_handler;
zend_stackuser_error_handlers_error_reporting;
zend_ptr_stackuser_error_handlers;
zend_ptr_stackuser_exception_handlers;
zend_error_handling_terror_handling;
zend_class_entry*exception_class;
/*timeoutsupport*/
inttimeout_seconds;
intlambda_count;
HashTable*ini_directives;
HashTable*modified_ini_directives;
zend_objects_storeobjects_store;
zval*exception,*prev_exception;
zend_op*opline_before_exception;
zend_opexception_op[3];
struct_zend_execute_data*current_execute_data;
struct_zend_module_entry*current_module;
zend_property_infostd_property_info;
zend_boolactive;
void*saved_fpu_cw;
void*reserved[ZEND_MAX_RESERVED_RESOURCES];
};
这里先简单看看,以后用到的时候再细说,
PHP里最基本的单元变量:
在PHP里定义一个变量再简单不过了
如
$a=1;
?>
PHP内核HASH表是什么
但是在内核中它是用一个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定义如下
#defineMAKE_STD_ZVAL(zv)\
ALLOC_ZVAL(zv);\//它归根到底等于(p)=(type*)emalloc(sizeof(type))
INIT_PZVAL(zv);
INIT_PZVAL定义在
#defineINIT_PZVAL(z)\看得出它是初始化参数
(z)->refcount__gc=1;\
(z)->is_ref__gc=0;
那么zval到底是什么呢
在zend/zend.h里面
typedefstruct_zval_structzval;//原来它是_zval_struct的别名
_zval_struct定义如下
typedefunion_zvalue_value{
longlval;//保存long类型的数据
doubledval;//保存double类型的数据
struct{
char*val;//真正的值在这里
intlen;//这里返回长度
}str;
HashTable*ht;
zend_object_valueobj;//这是一个对象
}zvalue_value;
struct_zval_struct{
zvalue_valuevalue;//保存的值
zend_uintrefcount__gc;//被引用的次数如果为1则只被自己使用如果大于1则被其他变量以&的形式引用。
zend_uchartype;//数据类型这也是为什么PHP是弱类型的原因
zend_ucharis_ref__gc;//表示是否为引用
};
如果还是不够清楚那么我们实战一下用C来创建一个PHP变量
这里需要一个扩展,PHP如果用C扩展模块这里就不说了
关键代码
PHP_FUNCTION(test_siren){
zval*value;
char*s="createaphpvariable";
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;
?>
就会输出“createaphpvariable”
OK,
大功告成
注意,我是为了让大家看到PHP内部创建变量的流程才采用C的形式创建变量,
绝对不推荐大家这样做。
还是一定要用PHP内部的内存管理机制分配并处理内存。
以上就是关于“PHP内核HASH表是什么”的内容,希望对大家有用。更多资讯请关注学步园。学步园,您学习IT技术的优质平台!