與 PHP V4 提供的特性相比,2004 年釋出的 PHP V5 在面向對象程式設計(OOP)和設計方面向前邁出了很大的一步。它提供了一些必要的改進,例如類可見性、合适的構造函數和解構函數、輸入提示和類反射(class-reflection)API。它為在 PHP 中進行進階的面向對象程式設計敞開了大門,并允許實作更加簡單的設計模式,以及更好的設計類和 API。
PHP V5.3 在 OOP 方面提供了大量漸進式補充。這些改進一直集中在文法補充和性能改進方面。首先,我們将檢視靜态方法和成員方面的新特性。
<a href="http://www.ibm.com/developerworks/cn/opensource/os-php-5.3new1/index.html#ibm-pcon">回頁首</a>
PHP V5 中的一個有用補充就是能夠将一個方法或類成員指定為靜态的(PHP V4 确實支援對方法和類成員的靜态通路,但是不能夠将方法或成員指定為專門用于靜态通路)。靜态通路特别适合實作單一設計模式,在這種模式中隻存在一個類執行個體。
PHP V5.3 提供一些特性來增強對類的靜态成員和方法的支援。我們将檢視最近添加的一種魔術方法:<code>__callStatic()</code>。
PHP V5 提供了一些可用于類内部的特别定義的方法,稱為魔術方法。當在類内部定義時,這些方法可以提供特殊的功能,并支援重載(允許一種方法接受不同類型的參數)和多态(允許不同資料類型使用相同的接口)。它們還允許通過 PHP 輕松地使用不同類型的 OOP 程式設計方法和設計模式。
在 PHP V5.3 中,添加了一種新的魔術方法:<code>__callStatic()</code>。它的工作方式類似于 <code>__call()</code> 魔術方法,後者的設計意圖是處理那些沒有在類中定義或對類不可見的方法的調用。然而,<code>__callStatic()</code> 是為了處理靜态方法調用,這使我們能夠更好地設計方法重載。下面給出了一個使用該方法的示例。
需要注意,PHP 确實加強了對 <code>__callStatic()</code> 方法的定義;它必須是公共的,并且必須被聲明為靜态的。同樣,<code>__call()</code> 魔術方法必須被定義為公共的,所有其他魔術方法都必須如此。
PHP 的一個優秀特性是可變變量。這表示可以使用某個變量的字元串值指定另一個變量的名稱。換句話說,可以執行與下面類似的操作。
這也适用于函數,甚至是類方法,如下所示。
PHP V5.3 的一個新特性就是在進行靜态調用時,能夠使指定的類名成為一個變量。這提供了一些新的機會,如下所示。
這一補充完善了 PHP 的可變變量特性,允許将它們應用到涉及 PHP 的所有情形。
讓我們檢視一個有關靜态方法和成員應用的更有用的增強:延遲靜态綁定(late static binding)。
在 V5.3 以前,PHP 存在的麻煩問題是如何處理靜态方法和成員。到目前為止,使用自身或 <code>__CLASS__</code> 進行的靜态引用都是在定義函數的類作用域中解析的。問題在于,如果類進行了擴充并且調用來自新的子類,那麼解析将是錯誤的。PHP V5.3 添加了延遲靜态綁定來解決這個問題。為了更好地進行解釋,我們在下面将建立一個具有靜态方法的類。
讓我們對這個類進行擴充。我們将在子類中重新定義成員 $name。
我們在清單 7 中進行了靜态調用。
該調用的輸出是字元串 <code>Foo</code>。這是因為在 <code>test()</code> 方法中進行的引用 <code>self::$name</code> 是在 <code>Foo</code> 類中完成的。這樣綁定的原因是:函數是在<code>Foo</code> 類中定義的。
PHP V5.3 添加了關鍵字 <code>static</code> 以允許針對目前類進行引用。是以将修改上面的 <code>Foo</code> 類以在清單 8 中使用該關鍵字,我們将看到輸出的内容變成了 <code>Bar</code>。
有關 <code>static</code> 關鍵字需要注意一點,它的工作方式與在非靜态上下文中的工作方式不同。這意味着普通的繼承規則沒有應用到靜态調用中。靜态關鍵字将僅僅嘗試在目前類中解析調用,而不是在定義函數的類中執行。這一點值得注意。
現在您已經了解了有關靜态方法和成員的增強,現在讓我們看一看 PHP V5 中新添的類,它們構成了非常有用的部分:标準 PHP 庫。
标準 PHP 庫(Standard PHP Library,SPL)是 PHP V5 中新增的接口和類的集合,旨在解決标準問題。這些問題包括實作可疊代的對象,使對象具有數組的行為或實作一個連結的清單。這些類和方法的優點是它們是原生的 PHP,這意味用 PHP 本身實作它們會獲得更快的速度。在很多情況下,這些類和方法還允許内部 PHP 函數直接使用這些對象,就像 Iterator 接口允許您使用 <code>foreach</code> 結構疊代對象一樣。
PHP V5.3 向 SPL 添加了更多的類。我們前面提到一個類就是在 SPL 類 <code>SplDoublyLinkedList</code> 中實作的雙重連結清單。它供其他兩個新 SPL 類使用:<code>SplStack</code>(實作一個棧)和 <code>SplQueue</code>(實作一個隊列)。
讓我們看一看如何使用 <code>SplStack</code> 類實作一個棧。
<code>SqlQueue</code> 也采取類似的方式,但是它像隊列那樣工作(先進先出;而不是像棧一樣最後一個項進棧,第一個項出棧)。此外,還存在堆實作(<code>SplHeap</code>),以及針對某些情況的特定隊列和堆實作(<code>SplMinHeap</code>、<code>SplMaxHeap</code> 和 <code>SplPriorityQueue</code>)。
另一個有用的補充是 <code>SplFixedArray</code> 類,顧名思義,這是一個固定大小的數組實作。然而,它的性能非常快 — 實際上它在基準測試中要比 PHP 内置數組實作快 10% 至 30%。造成這種速度優勢的原因是數組是固定大小的,而預設的 PHP 數組是可變大小的,并且不允許非數值型索引。清單 10 顯示了它的使用方法。
此外,添加了一些新的疊代器類:<code>FilesystemIterator</code> 和 <code>GlobIterator</code>。它們與 PHP 中的其他疊代器類使用相同的工作方式,但是它們分别針對不同的情況。
SPL 的另一個改變是現在的 PHP V5.3 通常啟用 SPL。在以前的 PHP V5 版本中,可以在編譯時禁用 SPL,但是 PHP V5.3 不能禁用 SPL。
SPL 中的新補充?? PHP 添加了一些有用的并且易于使用的功能,以及資料結構的實作,例如雙重連結清單、棧、堆和隊列。這些類可用于替換使用者空間實作,這将改進速度并更好地內建各種 PHP 函數和構造。
現在我們已經了解了 SPL 中的一些新内容,讓我們看一看 PHP V5.3 中的 OOP 如何通過循環垃圾收集獲得顯著的性能和記憶體使用改善。
垃圾收集是 PHP 開發人員在性能方面遇到的一個問題。PHP 有一個非常簡單的垃圾收集器,它實際上将對不再位于記憶體範圍(scope)中的對象進行垃圾收集。垃圾收集的内部方式是使用一個引用計數器,是以當計數器達到 0 時(意味着對該對象的引用都不可用),對象将被當作垃圾收集并從記憶體中删除。
這種方式工作得很好,但是如果一個對象使用父子關系引用另一個對象,那就會引發問題。在這種情況下,這些對象的引用計數器沒有被收集,是以這些對象使用的記憶體仍然屬于未引用的記憶體,并且直到完成請求後才能夠進行配置設定。下面看一下關于這種問題的例子。
在這種情況下,每當建立 <code>Parent</code> 類的執行個體并且該執行個體随後超出記憶體範圍時,記憶體不會被釋放,是以腳本在記憶體使用中不斷增加。有一些使用者空間解決方案可以解決這個問題。例如為父類建立一個解構函數将直接釋放子對象。這種解構器必須在解除父類引用之前進行調用。但是執行這些工作會使您的代碼也變得非常複雜。
在 PHP V5.3 中,垃圾收集器将檢測這些循環引用,并且能夠釋放它們所占用的記憶體,是以在執行腳本時 PHP 記憶體使用情況将保持平穩。當 <code>Parent</code> 類的每個引用被删除後,<code>Parent</code> 類中的 <code>Child</code> 類引用也将會被當作垃圾收集。
PHP 在支援面向對象程式設計方面經曆了長期的發展。PHP V4 時期的支援是比較弱的,但在 PHP V5 中得到顯著的改善,并且後續版本還會調整。現在,PHP V5.3 提供了一些令人興奮的改進,包括文法增強,例如新 <code>__callStatic()</code> 魔術方法、動态的靜态調用、延遲靜态綁定、靜态方法和成員支援。它為 SPL 添加了新的内容,包括雙重連結表、棧、堆和隊列的實作,使您獲得了一些常見的資料結構并且可以輕松使用它們。最後,期待已久的循環垃圾收集器是一個經過改進的垃圾收集器,它恰當地為這些循環執行個體釋放記憶體,解決了自引用類的記憶體和性能問題。所有這些特性使 PHP V5.3 成為一種更加強大的面向對象程式設計語言。