现在的位置: 首页 > 移动开发 > 正文

PHP内核HASH表是什么

2020年05月26日 移动开发 ⁄ 共 6358字 ⁄ 字号 评论关闭

  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技术的优质平台!

抱歉!评论已关闭.