【PHP核心學習】變數和資料類型
|=-----------------------------------------------------------------------=||=---------------------=[ PHP核心中的變數和資料類型]=--------------------=||=-----------------------------------------------------------------------=||=--------------------------=[ by d4shman ]=-----------------------------=||=-----------------------------------------------------------------------=||=-------------------------=[ May 6, 2014 ]=---------------------------=||=-----------------------------------------------------------------------=|
(_____ \| | | (_____ \ /\ / _____) | / ) _____) ) |__ | |_____) ) / \ | / | | / / | ____/| __)| (_____ ( / /\ \| | | |< < | | | | | | | | |__| | \_____| | \ \ |_| |_| |_| |_|______|\______)_| \_) (向phrack致敬!)
<--------------------------( Table of Contents )-------------------------->
0x01 變數的結構和類型 0x02 雜湊表--PHP的靈魂 0x03 常量 0x04 參考文獻<------------------------------------------------------------------------->
/////0x01 變數的結構和類型/////1.資料類型 1.1靜態類型語言(C/Java),編譯時間確定 1.2動態類型語言(php/python),運行時確定 1.3無類型語言(彙編),操作的底層儲存
2.php核心中所有的變數使用同一種資料結構zval來儲存,而這個結構同時表示php中各種資料類型,它不僅僅包含變數的值,也包含變數的類型。這就是php弱類型的核心。 php中的8中資料類型: 2.1標量類型: boolean, integer, float, string 2.2複合類型: array, object 2.3特殊類型: resource, null 3.zval結構體(在php源碼目錄下Zend/zend.h中定義): struct _zval_struct{ /*Variable information*/ zvalue_value value /*value, 變數的值*/ zend_uint refcount__gc /*reference count, 引用計數器*/ zend_uchar type /*active type, 變數的類型*/ zend_uchar is_ref__gc; /*變數是否被引用*/ }
4.變數類型: /*data types */ #define IS_NULL0 #define IS_LONG 1 #define IS_DOUBLE 2 #define IS_BOOL 3 #define IS_ARRAY4 #define IS_OBJECT5 #define IS_STRING 6 #define IS_RESOURCE7 #define IS_CONSTANT8 #define IS_CONSTANT_ARRAY9 #define IS_CALLABLE10 5.變數的值儲存 typedef union _zvalue_value { long lval; /*long、bool、resource類型*/ double dval ;/*double 類型*/ struct {/*string 類型, len儲存了字串的長度*/ char *val; int len; } str; HashTable *ht; /*數組, 用HashTable實現*/ zend_object_value obj; /*object 類型*/ } zvalue_value; 這裡之所以用共同體(union)是因為一個變數只可能有一種類型,符合共同體的特性,如果使用結構體則會浪費記憶體。 執行個體:建立一個值為10的整型變數lvar,用php指令碼的話很簡單,就是:$lvar = 10 而PHP核心中的實現可能就是類似下面這樣: zval lval; Z_TYPE(lvar) = IS_LONG; Z_LVAL(lvar) = 10; /////0x02 雜湊表--PHP的靈魂/////1.為什麼用雜湊表 雜湊表通常提供CRUD(Create, Read, Update, Delete)操作,設計合理的雜湊表中,這些操作時間複雜度為O(1),這也是它被鐘愛的原因。 hash(key) -> index 2.雜湊表的實現:結構體 bucket和_hashtable組成了完整的HashTable。 首先看bucket結構體(定義在 Zend/zend_hash.h): typedef struct bucket { ulong h; /*hash值*/ uint nKeyLength;/*key的長度*/ void *pData;/*要儲存的記憶體塊地址,通常是malloc來的地址*/ void *pDataPtr;/*儲存指標資料,不經過malloc的指標,防止產生記憶體片段*/ struct bucket *pListNext; /*bucket中具有同一hash值的下一個元素*/ struct bucket *pListLast; /*bucket中具有同一hash值的上一個元素*/ struct bucket *pNext;/*雙向鏈表的下一個元素*/ struct bucket *pLast; /*雙向鏈表的上一個元素*/ const char *arKey;/*儲存key*/ } Bucket; 可以看出bucket是一個雙向鏈表,這是為瞭解決多個key衝突的問題(即演算法導論中的連結法) 再看_hashtable結構體: typedef struct _hashtable { uint nTableSize; /*bucket數組的大小*/ uint nTableMask; uint nNumOfElements;/*HashTable中元素的個數*/ ulong nNextFreeElement;/*下一個可用的Bucket位置*/ Bucket *pInternalPointer/*遍曆HashTable元素*/ Bucket *pListHead;/*雙向鏈表表頭*/ Bucket *pListTail;/*雙向鏈表表尾*/ Bucket **arBuckets;/*Bucket數組*/ } HashTable; ======== 此處為HashTable的結構圖 ========
3.神奇的數字--33 見我原來的一篇部落格:http://blog.csdn.net/wusuopubupt/article/details/11479869 下面是PHP源碼中的一段注釋: /* * DJBX33A (Daniel J. Bernstein, Times 33 with Addition) * * This is Daniel J. Bernstein's popular `times 33' hash function as * posted by him years ago on comp.lang.c. It basically uses a function * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best * known hash functions for strings. Because it is both computed very * fast and distributes very well. * * The magic of number 33, i.e. why it works better than many other * constants, prime or not, has never been adequately explained by * anyone. So I try an explanation: if one experimentally tests all * multipliers between 1 and 256 (as RSE did now) one detects that even * numbers are not useable at all. The remaining 128 odd numbers * (except for the number 1) work more or less all equally well. They * all distribute in an acceptable way and this way fill a hash table * with an average percent of approx. 86%. * * If one compares the Chi^2 values of the variants, the number 33 not * even has the best value. But the number 33 and a few other equally * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great * advantage to the remaining numbers in the large set of possible * multipliers: their multiply operation can be replaced by a faster * operation based on just one shift plus either a single addition * or subtraction operation. And because a hash function has to both * distribute good _and_ has to be very fast to compute, those few * numbers should be preferred and seems to be the reason why Daniel J. * Bernstein also preferred it. * * * -- Ralf S. Engelschall <[email protected]> */
4.雜湊表的操作介面(省略了部分參數) 初始化HashTable:int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction); 添加新hash值: int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData) 尋找hash: int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData);
/////0x03 常量///// 1.常量的內部結構 typedef struct _zend_constant { zval value; int flags; /*常量標記,如 CONST_PERSISTENT | CONST_CS */ char *name; uint name_len; int module_number; } zend_constant;
2.define定義常量的過程 define的實現(定義在Zend/zend_builtin_functions.c),下面是部分核心代碼: ZEND_FUNCTION(define) { /* 檢查常量名是否存在 */ if (zend_memnstr(name, "::", sizeof("::") - 1, name + name_len)) { zend_error(E_WARNING, "Class constants cannot be defined or redefined"); RETURN_FALSE; } ... // 類常量定義 此處不做介紹 c.value = *val; zval_copy_ctor(&c.value); if (val_free) { zval_ptr_dtor(&val_free); } c.flags = case_sensitive; /* 大小寫敏感 */ c.name = zend_strndup(name, name_len); c.name_len = name_len+1; c.module_number = PHP_USER_CONSTANT; if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) { /*註冊常量*/ RETURN_TRUE; } else { RETURN_FALSE; } } 3.魔術常量 PHP中的魔術常量,雖然叫做常量,但它們的值實際上隨它們在代碼中的位置而變化的。 __LINE__ 檔案中的當前行號。 __FILE__ 檔案的完整路徑和檔案名稱。如果用在被包含檔案中,則返回被包含的檔案名稱。 __DIR__ 檔案所在的目錄。如果用在被包括檔案中,則返回被包括的檔案所在的目錄。它等價於 dirname(__FILE__)。 __FUNCTION__函數名稱 __CLASS__ 類的名稱。類名包括其被聲明的作用地區(例如 Foo\Bar)。 __TRAIT__ Trait 的名字。Trait 名包括其被聲明的作用地區(例如 Foo\Bar)。 __METHOD__類的方法名 __NAMESPACE__當前命名空間的名稱(區分大小寫)。此常量是在編譯時間定義的(PHP 5.3.0 新增)。 PHP核心會在詞法解析時將這些常量的內容賦值進行替換,而不是在運行時進行分析。 舉個例子: echo __LINE__; function demo() { echo __FUNCTION__; } demo(); ?> PHP已經在詞法解析時將這些常量換成了對應的值,以上的代碼可以看成如下的PHP代碼: echo 2; function demo() { echo "demo"; } demo(); ?>
=========== 此處涉及編譯原理知識,需補充。 =========== /////0x04 參考文獻/////
TIPI: http://www.php-internals.com/book/?p=chapt03/03-00-variable-and-data-types
-
1樓wusuopuBUPT昨天 14:06
-
本文github地址:https://github.com/wusuopubupt/phpLib/blob/master/PHP%E5%86%85%E6%A0%B8%E4%B8%AD%E7%9A%84%E5%8F%98%E9%87%8F%E5%92%8C%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B