程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP內核研究:HASH表和變量

PHP內核研究: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 << i) < nSize) { //調整為 2的n次方          i++;        }        ht->nTableSize = 1 << i;//HASH bucket大小   為 2的i次方  i=3 ,nTableSize最小值為8   }  //為了提高計算效率,系統自動會將nTableSize調整到最小一個不小於nTableSize的2的整數次方。也就是說,如果在初始化HashTable時指定一個nTableSize不是2的整數次方,系統將會自動調整nTableSize的值 <!--EndFragment-->      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裡 定義一個變量 再簡單不過了 如 <?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裡       <?php  test_siren(1);  echo $a;  ?>  就會輸出 “create a php variable” OK, 大功告成 注意,我是為了讓大家看到PHP內部創建變量的流程 才采用C的形式創建變量, 絕對不推薦大家這樣做. 還是一定要用PHP內部的內存管理機制分配並處理內存。    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved