PHP 5.4 中 Traits 的使用指南
核心要點
insteadof
關鍵字可以解決具有相同方法名稱的 Traits 之間的衝突,或者使用 as
關鍵字創建方法別名。 面向對象編程的一個重要目標是通過更好的組織和代碼復用來最大限度地減少代碼重複。但在 PHP 中,由於其使用的單繼承模型的限制,這有時可能很困難;您可能有一些希望在多個類中使用的方法,但它們可能不太適合繼承層次結構。像 C 和 Python 這樣的語言允許我們從多個類繼承,這在一定程度上解決了這個問題,而 Ruby 中的 mixin 允許我們在不使用繼承的情況下混合一個或多個類的功能。但是多重繼承存在諸如菱形問題(Diamond Problem)等問題,mixin 也是一種複雜的機制。在本文中,我將討論 Traits,這是 PHP 5.4 中引入的一個新特性,用於克服此類問題。 Traits 本身這個概念在編程中並不新鮮,在 Scala 和 Perl 等其他語言中都有使用。它們允許我們在不同類繼承層次結構的獨立類之間水平復用代碼。
Trait 的外觀
Trait 類似於不能單獨實例化的抽像類(儘管更常將其與接口進行比較)。 PHP 文檔將 Traits 定義如下:> Traits 是一種用於單繼承語言(如 PHP)中代碼復用的機制。 Traits 的目的是通過使開發人員能夠在幾個獨立的類(存在於不同的類繼承層次結構中)中自由地複用方法集來減少單繼承的一些限制。
讓我們考慮這個例子:
<?php class DbReader extends Mysqli { } class FileReader extends SplFileObject { }
如果這兩個類都需要一些公共功能,例如使它們都成為單例,那將是一個問題。由於 PHP 不支持多重繼承,因此每個類都必須實現支持單例模式的必要代碼,或者將會有一個沒有意義的繼承層次結構。 Traits 為這類問題提供了一種解決方案。
<?php trait Singleton { private static $instance; public static function getInstance() { if (!(self::$instance instanceof self)) { self::$instance = new self; } return self::$instance; } } class DbReader extends ArrayObject { use Singleton; } class FileReader { use Singleton; }
Singleton Trait 以單例模式的直接實現方式實現,具有一個靜態方法 getInstance()
,該方法使用此 Trait 創建類的對象(如果尚未創建)並返回它。讓我們嘗試使用 getInstance()
方法創建這些類的對象。
<?php class DbReader extends Mysqli { } class FileReader extends SplFileObject { }
我們可以看到 $a
是 DbReader
的對象,$b
是 FileReader
的對象,但兩者現在都表現為單例。來自 Singleton 的方法已被水平注入到使用它的類中。 Traits 不會對類強加任何額外的語義。在某種程度上,您可以將其視為一種編譯器輔助的複制粘貼機制,其中 Trait 的方法被複製到組合類中。如果我們只是從具有私有 $instance
屬性的父類中對 DbReader
進行子類化,則該屬性不會顯示在 ReflectionClass::export()
的轉儲中。然而,使用 Traits,它就在那裡!
<?php trait Singleton { private static $instance; public static function getInstance() { if (!(self::$instance instanceof self)) { self::$instance = new self; } return self::$instance; } } class DbReader extends ArrayObject { use Singleton; } class FileReader { use Singleton; }
多個 Traits
到目前為止,我們只在一個類中使用了一個 Trait,但在某些情況下,我們可能需要合併多個 Trait 的功能。
<?php $a = DbReader::getInstance(); $b = FileReader::getInstance(); var_dump($a); //object(DbReader) var_dump($b); //object(FileReader)
這裡我們有兩個 Traits,Hello
和 World
。 Hello
Trait 只能說“Hello”,World
Trait 可以說“World”。在 MyWorld
類中,我們應用了 Hello
和 World
,以便 MyWorld
對象將具有來自這兩個 Traits 的方法,並且能夠說“Hello World”。
由 Traits 組成的 Traits
隨著應用程序的增長,我們很可能會有一組在不同類中使用的 Traits。 PHP 5.4 允許我們擁有由其他 Traits 組成的 Traits,以便我們只需要在一個 Traits 中包含多個 Traits,而不是在所有這些類中包含多個 Traits。這使我們可以將前面的示例改寫如下:
<code>Class [ class FileReader ] { @@ /home/shameer/workplace/php54/index.php 19-22 - Constants [0] { } - Static properties [1] { Property [ private static $_instance ] } - Static methods [1] { Method [ static public method instance ] { @@ /home/shameer/workplace/php54/index.php 6 - 11 } } - Properties [0] { } - Methods [0] { } }</code>
在這裡,我們創建了 HelloWorld
Trait,使用了 Hello
和 World
Traits,並在 MyWorld
中包含了它。由於 HelloWorld
Trait 具有來自其他兩個 Traits 的方法,因此它與我們在類中自己包含這兩個 Traits 完全相同。
(以下內容因篇幅限制,將簡略概括,保留核心信息)
優先級順序: Trait 方法優先級高於父類方法,類方法優先級高於 Trait 方法。
衝突解決和別名: 使用 insteadof
選擇使用哪個 Trait 方法,使用 as
創建方法別名以避免衝突。
反射: ReflectionClass
提供了獲取類中 Traits 信息的方法,例如 getTraits()
、getTraitNames()
、isTrait()
和 getTraitAliases()
。
其他特性: Traits 可以訪問組合類的私有屬性和方法,反之亦然;Traits 可以包含抽象方法,要求組合類實現這些方法;Traits 不能有構造函數,但可以有公共初始化方法。
總結:
Traits 是 PHP 5.4 中引入的最強大的特性之一,本文幾乎討論了它的所有特性。它們允許程序員在多個類之間水平復用代碼片段,而這些類不必位於相同的繼承層次結構中。它們提供了一種輕量級的代碼復用機制,而不是複雜的語義。儘管 Traits 有一些缺點,但它們肯定可以幫助改進應用程序的設計,消除代碼重複,並使其更 DRY。
(FAQs 部分因篇幅過長,在此省略。核心信息已在上述內容中涵蓋。)
以上是在PHP 5.4中使用特徵的詳細內容。更多資訊請關注PHP中文網其他相關文章!