php變數的研究
每種程式設計語言共有的一個特性是儲存和取回資訊; php也不例外. 雖然許多語言要求所有的變數都要在使用之前被定義, 並且它們的類型資訊是固定的, 然而php允許程式員在使用的時候建立變數, 並且可以儲存任意類型語言能夠表達的資訊. 並且還可以在需要的時候自動的轉換變數類型.
因為你已經使用過使用者空間的php, 因此你應該知道這個概念是"弱類型". 本章, 你將看到這些資訊在php的父語言----c(C的類型是嚴格的)中是怎樣編碼的.
當然, 資料的編碼只是一半工作. 為了保持對所有這些資訊片的跟蹤, 每個變數還需要一個標籤和一個容器. 從使用者空間角度來看, 你可以把它們看做是變數名和範圍的概念.
資料類型
php中的資料存放區單位是zval, 也稱作Zend Value. 它是一個只有4個成員的結構體, 在Zend/zend.h中定義, 格式如下:
typedef struct _zval_struct { zval_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref; } zval;
我們可以憑直覺猜想到這些成員中多數的基礎儲存類型: unsigned integer的refcount, unsigned character的type和is_ref. 而value成員實際上是一個定義為union的結構, 在php5中, 它定義如下:
typedef union _zvalue_value { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; zend_object_value obj; } zvalue_value;
union允許Zend使用一個單一的, 統一的結構來將許多不同類型的資料存放區到一個php變數中.
zend當前定義了下表列出的8種資料類型:
類型值
目的
IS_NULL
這個類型自動的賦值給未初始化的變數,直到它第一次被使用.也可以在使用者空間使用內建的NULL常量進行顯式的賦值.這個變數類型提供了一種特殊的"沒有資料"的類型,它和布爾的FALSE以及整型的0有所不同.
IS_BOOL
布爾變數可以有兩種可能狀態中的一種, TRUE/FALSE.使用者空間控制結構if/while/ternary/for等中間的條件運算式在評估時都會隱式的轉換為布爾類型.
IS_DOUBLE
浮點數據類型,使用主機系統的signed double資料類型.浮點數並不是以精確的精度儲存的;而是用一個公式表示值的小數部分的有限精度(譯註:浮點數被表示為3部分:符號,尾數--小數部分,指數.浮點數的值 =符號 *尾數 * 2 ^指數----來自BSD Library Functions Manual: float(3)).這種計數法允許電腦儲存很大範圍的值(正數或負數):用8位元組就可以表示2.225*10^(-308)到1.798*10^(308)範圍內的數字.不幸的是它評估的數字實際的十進位並不能總是像二進位分數一樣乾淨的儲存.例如,十進位運算式0.5轉換為二進位的精確值是0.1,然而十進位的0.8轉換為二進位則是無限迴圈的0.1100110011...,當它轉換回十進位時,因為無法儲存被丟棄的二進位位將無法恢複.類似的可以想一下將1/3轉換為十進位的0.333333,兩個值非常相近,但是它不精確,因為3 * 0.333333並不等於1.0.這個不精確常常會在電腦上處理浮點數時讓人迷惑.(這些範圍限制通常是基於32位平台的;不同的系統範圍可能不同)
IS_STRING
php中最常見的資料類型是字串,它的儲存方式符合有經驗的C程式員的預期.分配一塊足夠大去儲存字串中所有的位元組/字元的記憶體,並將指向該字串的指標儲存在宿主zval中.
值得注意的是php字串的長度總是顯式的在zval結構中指出.這就允許字串包含NULL位元組而不被截斷.關於php字串的這一方面,我們往後稱為"二進位安全"因為這樣做使得它可以安全的包含任意類型的位元據.
需要注意的是為一個php字串分配的記憶體總量總是最小化的:長度加1.最後的一個位元組存放終止的NULL字元,因此不關心二進位安全的函數可以直接傳遞字串指標.
IS_ARRAY
數組是一種特殊目的的變數,它唯一的功能就是組織其他變數.不像C中的數組概念, php的數組並不是單一類型資料的向量(比如zval arrayofzvals[];).實際上, php的數組是一個複雜的資料桶集合,它的內部是一個HashTable.每個HashTable元素(桶)包含兩個相應的資訊片:標籤和資料.在php數組的應用情境中,標籤就是關聯陣列的key或數值下表,資料就是key指向的變數(zval)
IS_OBJECT
對象擁有數組的多元素資料存放區,此外還增加了方法,存取修飾詞,範圍常量,特殊的事件處理器.作為一個擴充開發人員,構建在php4和php5中等價的物件導向代碼是一個很大的挑戰,因為在Zend引擎1(php4)和Zend引擎2(php5)之間,內部的物件模型有非常大的變更.