文/朱先忠編譯
一、簡介
很幸運,php(做為現在的主流開發語言) 5.0中引入了對象重載技術。本文將探討對於方法__call(),__set()以及__get()進行重載的可能性。在對重載理論作簡單介紹後,我們將通過兩個例子直奔主題:第一例,實現持續存儲類;第二例,找到一種實現動態的getter/setter的方法。
二、什麼是對象重載?
在php(做為現在的主流開發語言)中談到對象重載時,我們要區別兩種類型:
·方法重載
·屬性重載
在方法重載的情況下,我們要定義一個魔術般的方法__call(),它將實現一個在相應類中對未定義方法的籠統調用。只有當你想存取類中未定義的方法時,這種籠統方法才會被調用。在沒有方法重載的情況下,下面的例子將導致php(做為現在的主流開發語言)顯示一條致命錯誤信息:Call to undefined method ThisWillFail::bar() in/some/directory/example.php(做為現在的主流開發語言) on line 9並流產程序的執行:
<?php(做為現在的主流開發語言)
class ThisWillFail {
public function foo() {
return "Hello World!";
}
}
$class = new ThisWillFail;
$class->bar();
?>
借助方法重載的幫助,代碼能夠捕獲到這種調用且能夠體面地給以處理。
屬性重載與方法重載差不多。這種情況下,類把讀/寫操作重定向(亦可稱代理)到類的屬性,這些屬性在類中沒有顯式定義。這裡的專門方法是__set()和__get()。依賴於錯誤報告等級,php(做為現在的主流開發語言)翻譯器通常在存取一個未定義的屬性時,或者發出一個通知,或者推遲一下並潛在地定義這個變量。而如果使用屬性重載,翻譯器卻可以在設置一個未定義的屬性時調用__set(),而在存取一個未定義的屬性值時調用__get()。
綜上所述,利用重載技術可以實現在象用php(做為現在的主流開發語言)這樣的動態語言進行時軟件開發時間的大大縮短。
理論介紹至此,下面分析具體編碼。
三、持續性存儲類舉例
下列代碼,通過使用屬性重載技術,用少於50行的php(做為現在的主流開發語言)代碼實現了上面所提到的持續性存儲類。術語persistable意味著類可以從一個數據結構中描述一個元素,並保持與底端存儲系統的同步。用編碼的解釋就是,外部代碼可以使用類來實現從一個數據庫表中選定一行。這樣,在程序運行時,可以直接存取類的屬性來操縱該行中的元素(讀/取)。在腳本結束時,php(做為現在的主流開發語言)將負責把更新的行數據回送到數據庫中去。
精心研讀下面代碼將有助於你理解什麼是屬性重載。
<?php(做為現在的主流開發語言)
//裝入PEAR的 <a href="http://pear.php(做為現在的主流開發語言).net/package/DB/">DB package</a>
require_once "DB.php(做為現在的主流開發語言)";
class Persistable {
private $data = array();
private $table = "users";
public function __construct($user) {
$this->dbh = DB::Connect("MySQL(和PHP搭配之最佳組合)://user:password@localhost/database");
$query = "SELECT id, name, email, country FROM " .
$this->table . " WHERE name = ?";
$this->data = $this->dbh->getRow($query, array($user),
DB_FETCHMODE_ASSOC);
}
public function __get($member) {
if (isset($this->data[$member])) {
return $this->data[$member];
}
}
public function __set($member, $value) {
// dataset的ID是只讀的
if ($member == "id") {
return;
}
if (isset($this->data[$member])) {
$this->data[$member] = $value;
}
}
public function __destruct() {
$query = "UPDATE " . $this->table . " SET name = ?,
email = ?, country = ? WHERE id = ?";
$this->dbh->query($query, $this->name, $this->email,