2011-03-06 96 views
5

我有一個連接到MySQL幷包裝所有PDO代碼的PHP數據庫類,並使用它來查詢數據庫。基本上在頁面控制器我提出一個新的對象:

$db = new Database($dbConfig); 

然後我就可以從數據庫中獲取數據,像這樣用準備好的查詢:

$params = array('username' => $username); 
$result = $db->preparedSelect('select password, salt from users where username = :username', $params); 

哪個副本PDO語句結果新ASSOC數組並僅將數據庫結果返回給調用頁面。我遍歷它們用一個簡單的foreach像這樣:

foreach ($result as $key => $val) 
{ 
    $password = $val['password']; 
    $salt = $val['salt']; 
} 

好了,所以可以說,我想另一個類用我的$ db對象,因此它可以在一些方法來訪問數據庫。目前,其他類看起來是這樣的:

class General 
{ 
    // Database object 
    private $db; 

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

行之有效,但我只是想知道如果構造應該是這樣的:

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

這應該意味着我通過它在通過引用而不是將對象複製到其他類中。我不希望在類內部有一個$ db對象的副本,我希望它使用現有的數據庫對象,所以我沒有使用內存的多個副本。

將PHP5作爲$ db或& $ db傳遞之間有什麼區別?從做一些閱讀,默認情況下PHP5通過引用傳遞對象,其他人說它現在是Java方式,有人說使用&可以創建一個硬鏈接,不管它是什麼。我很困惑。什麼是最好的方式來做到這一點?

非常感謝!

回答

8

有一個區別,但它並不是你可能想到的區別。

在PHP5中,持有對象的「$ db」基本上等同於C或C++中的「Foo *」。換句話說,$ db不存儲整個對象,它只是存儲一個小的令牌,讓代碼在必要時找到對象。當您按值傳遞此標記時,它與傳遞整數值而不是整個對象的副本一樣快。但是,如果您分配$ db,則不會更改調用方中的值,因爲您要更改持有令牌的局部變量以包含不同的令牌。

如果函數採用「& $ db」,那基本上等同於在C中傳遞「Foo **」,或者更準確地說,是一個在C++中使用「Foo * &」的函數。這個調用的速度是同樣快的,因爲它與傳遞的大小相同,但是在函數內部,如果您分配給$ db,它將更改調用程序中的$ db值,因爲「pass by reference」變量指向內存在調用者中持有令牌的位置。

要做到這一點,最好的方法是通過價值傳遞(不要使用「&」),除非您知道自己在做什麼以及爲什麼要這樣做。

+2

所以,基本上如果我做_construct($ db),然後更改$ db對象內的值例如$ db-> testvar = 1我將在內存中有兩個$ db對象,原始的和testvar包含'1'的新對象。是對的嗎? 如果我做_construct(&$ db),然後分配$ db-> testvar = 1,我應該影響原始對象,並且只有一個$ db對象實例在內存中。是對的嗎? – zuallauz 2011-03-06 09:42:46

+5

不,您將在兩種情況下都有一個具有更改值的對象,因爲在任何情況下都不會複製對象本身。在第一個函數中,如果你執行'$ db = null',調用者仍然有它原來的$ db,而在第二個函數中,調用者將不再擁有原始的$ db。 – Anomie 2011-03-06 16:04:30

3

這是一個很好的問題。

您可以通過打開$ db句柄,將它傳遞給一個函數,並通過===運算符檢查它們來確保它們是同一個對象,從而進行測試。

+1

我曾做過一個試驗,他們似乎是完全相同的對象。我認爲你必須使用克隆$ db實際製作原始$ db對象的副本。否則,您對另一個類中的$ db對象所做的任何更改都會更新原始內容。 – zuallauz 2011-03-06 10:16:23

3

這對靜態方法來說是一件好事。這就是有多少框架完成相同的任務。

class DB 
{ 
    private static $db = FALSE: 

    public static function init($dbConfig) 
    { 
     if(! self:$db) 
     { 
     self::$db = new Database($dbConfig); 
     } 
    } 

    public static function preparedSelect($sql, $params) 
    { 
     if(! self::$db) 
     { 
     die("call the init method first"); 
     } 

     // db stuff, where you would call $this->db call self::$db 
    } 
} 

所以,在你想調用數據庫所有你需要做的就是你的其他類:

class General 
{ 
    public function __construct() 
    { 
     DB::init($dbConfig); 
    } 

    public function someMethod() 
    { 
     $params = array('username' => $username); 
     $result = DB::preparedSelect('select password, salt from users where username = :username', $params); 

    } 
} 
+1

我正要爲此使用靜態方法,但是經過研究表明,像General類(當前是DB)的依賴關係不會立即顯現出來 - 並且可能導致混淆。不應該以這種方式使用靜態方法/單例 - 取而代之*應該使用Dependency Injection * /顯式地將該變量傳遞給構造函數,以便可以清楚地看到哪些類依賴於:) – Jimbo 2013-03-01 10:30:40

相關問題