天天看點

PHP變量和資料類型一、變量的結構和類型二、常量三、預定義變量四、靜态變量五、類型提示的實作六、變量的生命周期七、資料類型轉換

程式設計語言可以分為三大類

1. 靜态類型語言,比如:C/Java等,在靜态語言類型中,類型的檢查是在編譯期(compile-time)确定的。

2. 動态語言類型,比如:PHP,python等各種腳本語言,這類語言中的類型是在運作時确定的。

3. 無類型語言,比如:彙編語言,彙編語言操作的是底層存儲,他們對類型毫無感覺。

1)變量的存儲結構

在官方的PHP實作内部,所有變量使用同一種資料結構(zval)來儲存。 它不僅僅包含變量的值,也包含變量的類型。

在PHP中,存在8種變量類型,可以分為三類:

a. 标量類型: boolean、integer、float(double)、string

b. 複合類型: array、object

c. 特殊類型: resource、NULL

變量存儲結構如下:

type的值可以為: IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE之一。

2)變量的值存儲

上面的value是個聯合體,正因為是這樣,才能做到弱類型,聯合體如下:

3)哈希表(HashTable)

a. 鍵(key):用于操作資料的标示,例如PHP數組中的索引,或者字元串鍵等等。

b. 槽(slot/bucket):哈希表中用于儲存資料的一個單元,也就是資料真正存放的容器。

c. 哈希函數(hash function):将key映射(map)到資料應該存放的slot所在位置的函數。

d. 哈希沖突(hash collision):哈希函數将兩個不同的key映射到同一個索引的情況。

4)PHP的哈希實作

PHP的大部分的語言特性都是基于哈希表實作的, 例如:變量的作用域、函數表、類的屬性、方法等,Zend引擎内部的很多資料都是儲存在哈希表中的。

PHP中的哈希表是使用拉鍊法來解決沖突的,Zend為了儲存資料之間的關系使用了雙向連結清單來連結元素。

拉鍊法如下圖所示:

圖中,”John Smith”和”Sandra Dee” 通過哈希函數都指向了152 這個索引,該索引又指向了一個連結清單, 在連結清單中依次存儲了這兩個字元串。

Zend引擎哈希表結構和關系如下:

a. Bucket結構體維護了兩個雙向連結清單,pNext和pLast指針分别指向本槽位所在的連結清單的關系。

b. 而pListNext和pListLast指針指向的則是整個哈希表所有的資料之間的連結關系。

c. HashTable結構體中的pListHead和pListTail則維護整個哈希表的頭元素指針和最後一個元素的指針。

PHP核心會在詞法解析時将這些常量的内容指派進行替換,而不是在運作時進行分析。

1)常量的存儲結構

常量是在變量的zval結構的基礎上添加了一額外的元素。

1. CONST_CS:常量大小寫敏感

2. CONST_PERSISTENT:常量需要持久化;如果是非持久常量,會在RSHUTDOWN階段就将該常量釋放,否則隻會在MSHUTDOWN階段将記憶體釋放。使用者定義的常量都是非持久化的,通常擴充和核心定義的常量會設定為持久化。

3. CONST_CT_SUBST:Allow compile-time substitution(在編譯時可被替換)。在PHP核心中這些常量包括:TRUE、FALSE、NULL、ZEND_THREAD_SAFE和ZEND_DEBUG_BUILD五個。

PHP常量的定義過程如下:

2)标準常量

PHP内置定義的常量,他們屬于标準常量。如錯誤報告級别E_ALL, E_WARNING等。

這些常量都是持久化常量。

3)魔術常量

PHP中有七個魔術常量,他們的值其實是變化的,它們的值随着它們在代碼中的位置改變而改變。 是以稱他們為魔術常量。

  $_GET,$_POST,$_SERVER,$_FILES等變量,會在PHP腳本運作之前就将它們加入到HashTable資料類型的符号表中。

  由于都存儲在一個地方,是以在某個局部函數中使用類似于$GLOBALS變量這樣的預定義變量, 如果在此函數中有改變的它們的值的話,這些變量在其它局部函數調用時會發現也會同步變化。

  通常意義上靜态變量是靜态配置設定的,他們的生命周期和程式的生命周期一樣, 隻有在程式退出時(RSHUTDOWN)才結束期生命周期,這和局部變量相反,局部變量隻有在函數執行時才會存在。 通常,當一個函數執行完畢,它的局部變量的值就已經不存在,而且變量所占據的記憶體也被釋放。

靜态變量可以分為3中:

1)靜态全局變量:PHP中的全局變量(預定義變量等)也可以了解為靜态全局變量,因為除非明确unset釋放,在程式運作過程中始終存在。

2)靜态局部變量:也就是在函數内定義的靜态變量,Zend為每個函數配置設定了一個私有的符号表(EG(active_op_array)->static_variables)來儲存該函數的靜态變量。

3)靜态成員變量:這是在類中定義的靜态變量,和執行個體變量相對應,靜态成員變量屬于類,不屬于某個執行個體,是以可以在所有執行個體中共享。

PHP5中引入了類型提示這個概念。在定義方法參數時,同時定義參數的對象類型。

下面的示例代碼就是類型提示,但是在引用的時候傳入1,就會報錯。

類型提示的實作有2種:

1)參數聲明時的類型提示,例如“$arr=[1,2];”

2)函數或方法調用時的類型提示(上面的示例代碼)

在ZE進行詞法和文法的分析之後,生成具體的opcode,這些opcode最終被execute函數解釋執行。

1)變量的聲明和指派

在使用一個變量時,我們不需要聲明,也不需要初始化,直接對其指派就可以使用。

當指派的時候,zval結構中的refcount_gc預設為1,當引用這個值的時候,會加1。

2)變量的作用域

變量按作用域類型分為:全局變量和局部變量。

與JavaScript不同,得益于閉包的特性,JavaScript可以在函數中調用函數外的變量,而PHP不行。下面的代碼是錯誤的:

a. 全局變量會儲存在symbol_table中, 也就是頂層作用域中的變量。

b. 函數或者對象的方法在被調用時會建立active_symbol_table來儲存局部變量。

c. 函數中的靜态變量存放在私有的符号表(EG(active_op_array)->static_variables)中。是以不會在函數結束的時候銷毀。

3)global

global語句的作用是定義全局變量,也就是将變量放到symbol_table中。

将上面的代碼修改一下,增加一個global聲明:

1)隐式類型轉換

a. 直接的變量指派操作

b. 運算式結果對變量的指派操作

a. 隐式轉換null的時候,最後輸出的是空

b. boolean轉換成了0或1

c. 雖然array最後輸出了,但最後還是報錯。

d. 而類是直接報錯,沒有輸出。

2)顯示類型轉換

PHP中允許的強制類型有:

a. (int), (integer) 轉換為整型

b. (bool), (boolean) 轉換為布爾類型

c. (float), (double) 轉換為浮點類型

d. (string) 轉換為字元串

e. (array) 轉換為數組

f. (object) 轉換為對象

g. (unset) 轉換為NULL,這個還是第一次見到

參考文檔:

    本文轉自 咖啡機(K.F.J)   部落格園部落格,原文連結:http://www.cnblogs.com/strick/p/5035548.html,如需轉載請自行聯系原作者