2015-10-17 167 views
1

在我使用類數據庫連接,這樣的時刻:數據庫連接用靜態方法

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

如果我需要它的另一種方法,我用這樣的:

public function getElementbyID() { 
    $stmt = $this->db->prepare("SELECT ... 

但如何我在靜態方法中使用它嗎? 我不能夠使用$this->db

public static function getElementbyID() { 
    $stmt = $this->db ->prepare("SELECT ... 

如何使用SomeClass::getElementFromDB(),但在功能上仍然使用,我在__construct拿到了數據庫連接?

我不想像這樣使用它:SomeClass::getElementFromDB($db)並且我不想創建新的數據庫連接,因爲我已在$db中有一個。

或者 - 通常 - 這是如何完成的?

謝謝!

回答

1

如果要以靜態方式使用類,那麼必須將該類的所有屬性和方法重構爲靜態。 這是一個類模板類應該是,恕我直言:

class Element 
{ 
    protected static $db; 

    public static function setConnection(PDO $pdo) 
    { 
     self::$db = $pdo; 
    } 

    public static function getElementByID($id) 
    { 
     // use self::$db to retrieve information 
    } 
} 

// then you can use it directly without instantiate an instance 
$element = Element::getElementByID($id); 

基礎上要含蓄或明確調用setConnection()注入一個數據庫連接的東西。你可以用它明確地想:

Element::setConnection($pdo); 
$element = Element::getElementByID($id) 

或致電它隱含隱藏所有的設置(可能要通過建立一個單獨的數據庫類,以提供PDO實例,以每類使用Singleton模式在此)

class Database 
{ 
    protected static $db; 

    private function __construct(){}; 

    public static function getPdo() 
    { 
     if (!$db) self::$db = new Pdo(); 
     return self::$db; 
    } 
} 

class Element 
{ 
    public static function getElementByID($id) 
    { 
     // all the code like above 

     // call setConnection implicitly 
     self::setConnection(Database::getPdo()); 
     // use self::$db to retrieve information 
    } 
} 
// and just simply use 
$element = Element::getElementByID($id); 

你也可以使用Database::getPdo()每次一類需要一個連接,所以只有一個連接可重複使用許多時間。

問候,

+0

謝謝你的回答。正如我所看到的,所以我無法使用我已有的數據庫連接,並且不得不爲此類和其他靜態類再次使用它。 – Haudegen

+0

如果你已經有了一個數據庫連接並且想要重用它,那麼你必須將它注入到某個地方的類中,你可以隱式地或顯式地將它注入。我已經更新了答案以反映這一點。問候, –

0

我已經編寫了一個簡單的類可以添加功能這一點,你也可以做的更好,更高效。

<?php 
class Database 
    { 
     private $conn; 
     private $handle; 

     public static function __construct() 
     { 
     $dbhost = "localhost"; 
     $dbname = "pdo_test"; 
     $dbuser = "root"; 
     $dbpass = ""; 
     $charset = "utf8"; 

     /** 
     * -database driver, host, db (schema) name and charset, as well as less frequently used port and unix_socket are going to DSN 
     * -username and passwword are going to constructor 
     * -al other options go to options array 
     */ 

     $dsn = "mysql:host=$dbhost;dbname=$dbname;charset=$charset"; // DSN is a semicolon-delimited string consist of param = vale pairs.(DSN = Data Source Name) 
     try 
     { 
      $this->conn = new PDO($dsn, $dbuser, $dbpass, $opt); 
      //echo "Database connection successful.<br />"; 
     } 
     catch(PDOException $e) 
     { 
      echo "Error in database connection !!!<br />"; 
      echo $e->getMessage(); 
     } 
     } 

     public static function test($test) 
     { 
      echo "<br />".$test; 
     } 

     public static function __destruct() 
     { 
      $this->conn = null; 
      if(!$this->conn) 
      { 
     // echo "<br />database disconnected !!"; 
      } 
     } 
    } 

    Database::test("your query or table name and condition according to your functions"); 
+0

謝謝你的回答,但那不是我問的問題!我已經有一個數據庫類,它只是連接到一個靜態類。 – Haudegen

2

似乎有兩個主要問題,導致人們在課堂中包裝PDO代碼。

首先是需要調用數據庫一次並重用數據庫連接。例如,您不希望在每個Model函數內調用數據庫,因爲它會生成太多的數據庫連接,通常連接的數量會超過數據庫服務器允許的數量。

接下來是要阻止必須將數據庫連接變量(例如,$conn)傳遞給函數。 這可以通過示例來說明,因爲'select($ table,$ where)'優於'select($ conn,$ table,$ where)'。

有幾個微框架/類/庫爲你做這個。 一些較好的有:

或 - 通常 - 這是如何完成的?

就我個人而言,我更喜歡使用「幾乎」普通PDO調用的程序代碼(使用全局$ dbh變量來保存數據庫連接)。

要做到這一點,我先建一個DB()函數來存放數據庫連接:

function db($dsn=null) 
{ 
    global $dbh; 
    if(isset($dbh)) { 
     return $dbh; 
    } else { 
     $dbh = new PDO($dsn); 
     $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 
     $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 
     $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
     return $dbh; 
    } 
} 

用法:

db("sqlite:articles.db"); 

$stmt = db()->prepare("INSERT INTO `article` (`id`,`title`,`body`) VALUES (:id, :title, :body)"); 
$stmt->execute([ ':id'=>$id, ':title'=>$title, ':body'=>$body ]); 

或者:

$stmt = db()->prepare("SELECT * FROM `article` WHERE `id`=:id"); 
$stmt->execute([':id'=>542]); 
$row = $stmt->fetch(PDO::FETCH_OBJ); 
echo $row->id; 
... 

它甚至作品在函數內允許我使用簡單的語法創建我自己的模型函數:

db("sqlite:articles.db"); 

print_r(select_article("542")); 

function select_article($id) { 
    // Note that we use db() inside the function, without adding a $conn variable 
    $stmt = db()->prepare("SELECT * FROM `article` WHERE `id`=:id AND published=1"); 
    $stmt->execute([':id'=>$id]); 
    return $stmt->fetch(PDO::FETCH_ASSOC); 
} 

function insert($table,$data) { 
    ... 
    $stmt = db()->prepare("INSERT INTO `article` (`id`,`title`,`body`) VALUES (:id, :title, :body)"); 
    $stmt->execute([ ':id'=>$id, ':title'=>$title, ':body'=>$body ]); 
} 
+0

我在全球空間中使用$ dbh有點不高興。我必須非常關心這個嗎?謝謝您的回答! – Haudegen

+0

主要風險是訪問控制(任何代碼都可以使用全局變量)。爲了使varname不太可能干擾其他代碼,可以將$ dbh重命名爲一個唯一的var名稱$ dbh983252。 全局變量需要在函數之間共享數據庫對象。你會在這個問題中找到關於全局變量利弊的討論:[替換全局變量,如何和爲什麼](http://stackoverflow.com/questions/6998974/replacing-the-global-variables-how-and-爲什麼)。 –