高級PHP V5 對象研究

高級PHP V5 對象研究
本文介紹瞭PHP V5一些更高級的面向設計的特性。其中包括各種對象類型,它們允許將系統中的組件相互分離,創建可重用、可擴展、可伸縮的代碼。


  領會暗示 

  首先介紹一下對象類型和類型提示的優點。一個類定義一種類型。從該類實例化的任何對象屬於該類定義的類型。所以,使用 Car 類創建 Car 對象。如果 Car 類繼承 Vehicle 超類,則 Car 對象還將是一個 Vehicle 對象。這反映瞭我們在現實世界中分類事物的方法。但正如您將看到的,類型不僅僅是分類系統元素的有用方法。類型是面向對象編程的基礎,因為類型是良好一致的行為的保證。許多設計技巧來自該保證。

  “開始瞭解 PHP V5 中的對象”展示對象為您保證瞭接口。當系統傳遞 Dictionary 對象時,您可以確定它具有 $translations 數組和 summarize() 方法。相反,關聯數組不提供相同級別的確定性。要利用類提供的清晰接口,需要知道您的對象實際上是 Dictionary 的一個實例,而不是某個 imposter。可以用 instanceof 操作符來手動驗證這一點,該操作符是 PHP V5 引入的介於對象實例和類名之間的一個便捷工具。

   instanceof Dictionary

  如果給定對象是給定類的實例,則 instanceof 操作符解析為真。在調用方法中第一次遇到 Dictionary 對象時,可以在使用它之前檢查它的類型。

if ( $en instanceof Dictionary ) {
 print $en->summarize();
}

  但是,如果使用 PHP V5 的話,可以將對象類型檢查構建到類或方法聲明中。

  在“開始瞭解 PHP V5 中的對象”中,重點介紹兩個類:Dictionary,它存儲術語和翻譯, DictionaryIO,它將 Dictionary 數據導出(導入)自(至)文件系統。這些特性使得將 Dictionary 文件發送到第三方翻譯器變得容易,第三方翻譯器可以使用自己的軟件來編輯數據。然後,您可以重新導入已處理的文件。清單 1 是 Dictionary 類的一個版本,它接受一個 DictionaryIO 對象,並將其存儲以備將來使用。

  清單 1. 接受 DictionaryIO 對象的 Dictionary 類的一個版本

class Dictionary {
 public $translations = array();
 public $type =”En”;
 public $dictio;

 function addDictionaryIO( $dictio ) {
  $this->dictio=$dictio;
 }

 function export() {
  if ( $this->dictio ) {
   $this->dictio->export( $this );
  }
 }
}

class DictionaryIO {
 function export( $dict ) {
  print “exporting dictionary data “.”($dict->type)
“;
 }
}

$en = new Dictionary();
$en->addDictionaryIO( new DictionaryIO() );
$en->export();

// output: 
// dumping dictionary data (En)

  DictionaryIO 類具有單個方法 export(),它接受一個 Dictionary 對象,並使用它來輸出假消息。現在,Dictionary 具有兩個新方法:addDictionaryIO(),接受並存儲 DictionaryIO 對象; export(),使用已提供的對象導出 Dictionary 數據 —— 或者是在完全實現的版本中。

  您可能會疑惑為什麼 Dictionary 對象不僅實例化自己的 DictionaryIO 對象,或者甚至在內部處理導入導出操作,而根本不求助於第二個對象。一個原因是您可能希望一個 DictionaryIO 對象使用多個 Dictionary 對象,或者希望存儲該對象的單獨引用。另一個原因是通過將 DictionaryIO 對象傳遞給 Dictionary,可以利用類切換或 多態性。換句話說,可以將 DictionaryIO 子類(比如 XmlDictionaryIO)的實例傳遞給 Dictionary,並更改運行時保存和檢索數據的方法。

  圖 1 顯示瞭 Dictionary 和 DictionaryIO 類及其使用關系。

正如所顯示的,沒有什麼阻止編碼器將完全隨機的對象傳遞給 addDictionaryIO()。隻有在運行 export() 時,才會獲得一個類似的錯誤,並發現已經存儲在 $dictio 中的對象實際上並沒有 export() 方法。使用 PHP V4 時,必須測試本例中的參數類型,以絕對確保編碼器傳遞類型正確的對象。使用 PHP V5 時,可以部署參數提示來強制對象類型。隻將所需的對象類型添加到方法聲明的參數變量中,如清單 2 所示:

  清單 2. 將對象類型添加到方法聲明的參數變量中

function addDictionaryIO( DictionaryIO $dictio ) {
 $this->dictio=$dictio;
}

function export() {
 if ( $this->dictio ) {
  $this->dictio->export( $this );
 }
}

  現在,如果客戶機編碼器試圖將類型錯誤的對象傳遞給 addDictionaryIO(),PHP 引擎將拋出一個致命錯誤。因此,類型提示使得代碼更安全。不幸的是,提示僅對對象有效,所以不能在參數列表中要求字符串或整數。必須手動測試這些原類型。

  即使可以保證 addDictionaryIO() 將獲得正確的對象類型,但不能保證該方法被首先調用。export() 方法測試 export() 方法中 $dictio 屬性的存在,從而避免錯誤。但您可能希望更嚴格一些,要求 DictionaryIO 對象傳遞給構造函數,從而確保 $dictio 總是被填充。

  調用覆蓋方法

  在清單 3 中,XmlDictionaryIO 集成 DictionaryIO。而 DictionaryIO 寫入並讀取序列化數據,XmlDictionaryIO 操作 XML,可以與第三方應用程序共享。XmlDictionaryIO 可以覆蓋其父方法(import() 和 export()),也可以選擇不提供自己的實現(path())。如果客戶機調用 XmlDictionaryIO 對象中的 path() 方法,則在 DictionaryIO 中實現的 path() 方法被調用。

  事實上,可以同時使用這兩種方法。可以覆蓋方法並調用父實現。為此,使用新關鍵字 parent。用范圍解析操作符和所討論方法的名稱來使用 parent 。例如,假設需要 XmlDictionaryIO 使用當前工作目錄(如果有一個可用)中叫做 xml 的目錄;否則,它應使用由父 DictionaryIO 類生成的默認路徑,如清單 3 所示:

  清單 3. XmlDictionaryIO 使用 xml 目錄或由 DictionaryIO 類生成的默認路徑

class XmlDictionaryIO extends DictionaryIO {

 function path( Dictionary $dictionary, $ext ) {
  $sep = DIRECTORY_SEPARATOR;
  if ( is_dir( “.{$sep}xml” ) ) {
   return “.{$sep}xml{$sep}{$dictionary->getType()}.$ext”;
  }
  return parent::path( $dictionary, $ext );
 }
// …

  可以看到,該方法檢查本地 xml 目錄。如果該測試失敗,則它使用 parent 關鍵字指派給父方法。

本新聞共3頁,當前在第1頁  1  asp”>2  3  

子類和構造函數方法

  parent 關鍵字在構造函數方法中尤其重要。如果在子類中不定義構造函數,則 parent 構造函數代表您被顯式調用。如果在子類中不創建構造函數方法。則調用父類的構造函數並傳遞任何參數是您的責任,如清單 4 所示:

  Listing 4. Invoking the parent class’s constructor

class SpecialDictionary extends Dictionary { 
 function __construct( $type, DictionaryIO $dictio, $additional ) {
  // do something with $additional
  parent::__construct( $type, $dictio );
 }
}


抽象類和方法

  雖然在父類中提供默認行為是完全合法的,但這可能不是最巧妙的方法。對於啟動器,您必須依賴子類的作者來理解它們必須實現 import() 和 export(),才能在 broken 狀態創建類。而且,DictionaryIO 類實際上是兄弟,而不是父子。XmlDictionaryIO 不是 DictionaryIO 的特例;相反,它是一種備選實現。

  PHP V5 允許定義部分實現的類,其主要角色是為它的子女指定核心接口。這種類必須聲明為抽象。


abstract class DictionaryIO {}


  抽象類不能實例化。必須創建子類(即,創建繼承它的類),並創建該子類的實例。可以在抽象類中聲明標準和抽象方法,如清單 5 所示。抽象方法

發佈留言