2011-01-29 33 views
1

關於我的帖子:problems when extending a PHP Class使用擴展類(PHP)時的最佳技巧

什麼是最佳解決方案?爲什麼?

 

$query = $this->Execute("SELECT * FROM $table"); 
$total = $this->NumRows($query); 
 

或者

 

$query = DBManager::Execute("SELECT * FROM $table"); 
$total = DBManager::NumRows($query); 
 

或者

 

$query = parent::Execute("SELECT * FROM $table"); 
$total = parent::NumRows($query); 
 
+0

如果你重寫執行函數,你需要使用$ this,如果不是,我認爲其他選項是最好的方式,我不知道[parentClassName]或父類之間是否存在任何差異,但我會選擇第二個一 – raultm 2011-01-29 11:07:25

回答

0

有靜態之間調用的功能的差異(選項2和3)並調用它們作爲非靜態功能。它

0
  • $this點取決於你的整個設置的類的當前實例
  • DBManager指向父類,但當然,如果更改其名稱,則必須更改代碼。
  • parent指向這個繼承的類,不管它的名字。

因此,在這個例子中,我不認爲它很重要,沒有關於如何使用你的類和實例的進一步細節。但是,例如,如果您打算擁有多個DB類實例,則至少如果要存儲查詢或結果而不覆蓋它們(如raultm建議的那樣),則可能應該使用$this

2

當您擴展一個類時,除了任何子定義之外,子類還可以調用父類的所有公共和受保護的方法和屬性。如果您不需要重寫父的方法,而只是希望地方使用它們的孩子裏面,使用

public function somethingUsingExecute() 
{  
    $query = $this->Execute("SELECT * FROM $table"); 
    … 
} 

如果您需要在子類覆蓋execute也想調用該方法與母公司的原始功能,使用

public function execute($table) 
{ 
    // can do something not in parent before parent call 
    $query = parent::Execute("SELECT * FROM $table"); 
    // can do something not in parent after parent call 
} 

的靜態調用

$query = DBManager::Execute("SELECT * FROM $table"); 

是你應該忘記它存在的原因,因爲你正在將一個類名硬編碼到using類中,並將方法調用耦合到全局作用域。兩者都很難測試和維護。我不會詳細討論,因爲這已經在SO之前討論過了。只要給它一個搜索。


關於該User/DBManager示例的「最佳技巧」根本不會使用繼承。繼承創建一個is-a關係。孩子是父母的特例。但用戶不是一個DBManager(我會稱它爲DbAdapter btw)。

DBManager類的職責是允許訪問數據庫。你的用戶沒有這個責任。它使用 DBManager來訪問數據庫,但它確實需要知道如何做到這一點。DBManager已經做到了。

任何類別使用應該注入/聚合另一個類。所以,你應該做的是:

class User … 

    protected $db; 
    protected $isAuthenticated = FALSE; 

    public function __construct($db) 
    { 
     $this->db = $db; 
    } 

    public function authenticate($username, $password) 
    { 
     if($this->db->query('SELECT … ')) { 
      $this->isAuthenticated = TRUE; 
     } 
     return $this->isAuthenticated; 
    } 

    … 
} 

然後,你可以做

$db = new DBManager; 
$john = new User($db); 
$john->authenticate('JohnDoe', 'jd/12345'); 
$jane = new User($db); 
$jane->authenticate('JaneDoe', 'jd/67890'); 
$logger = new DBLogger($db); 
$logger->log('something to db'); 

注入DB類具有您可以在其他使用類重用現有DBManager實例的好處。如果擴展DBManager類,則每個新實例都將創建一個到數據庫的新連接,這是出於性能原因而不受歡迎的。

0

我會選擇第二個選項去,如果我們僅限於您的選項(否則閱讀下面的第3項),因爲:

1)當你寫

$query = $this->Execute("SELECT * FROM $table"); 
$total = $this->NumRows($query); 

它接縫像你有一個類,它執行查詢(所有類型),並處理一些特定查詢的結果(在你的案例中有多行)。想象你有兩個實體,它們都存儲在不同的表中,你將有兩個類,的其中一個將重複Execute方法邏輯,或者一個實體DAO將使用另一個執行它的Execute方法(但是這些實體可以是多數會被不相關的,所以你會害了OOP原則)

2)現在你的最後一種情況

$query = parent::Execute("SELECT * FROM $table"); 
$total = parent::NumRows($query); 

比以前的更好,但在這種情況下,你的DAO是從一個類,繼承了執行查詢執行......我不確定這是否是正確的方式,想象一下你有兩個不同的存儲區,比如數據庫和xml,從第一個將使用SQL的信息中檢索信息,對於最後一個,它可能是XPath ;要使用存儲,您將使用相同的界面和兩個實現,而不是問題 - 要爲您的User類繼承哪一個?沒有人,他們沒有關係;用戶實體不應該知道它存儲在哪裏。

3)最後一種情況

$query = DBManager::Execute("SELECT * FROM $table"); 
$total = DBManager::NumRows($query); 

聽起來像是委託(對不起,我沒那麼熟悉PHP),在這裏你指定要使用的類來處理查詢,對我來說,當我讀到這代碼,它聽起來像Execute/NumRows是DBManager類的靜態方法(再次抱歉,我只是使用我的架構知識來幫助你和基本約定,例如Java讀取你的代碼)。在這種情況下,我會建議你創建DBManager的實例,然後使用它:

class UserDAO { 
    private $storageManager = new DBManager(); 

    ... 
    $query = $storageManager::Execute("SELECT * FROM $table"); 
    $total = $storageManager::NumRows($query); 
    .... 
} 

像這樣(請糾正我,如果我在PHP代碼出錯了,現在只是看它像「的方式去',抽象算法描述;)。在這種情況下,如果必須切換到另一個DBManager實現,那麼只需更改行private $storageManager = new DBManager();即可。