2017-02-08 58 views
-1

我得到這個PDO數據庫類每次使用PDO數據庫類而不創建新連接?

class clsDatabase{ 
    // db settings 
    private $host = 'localhost'; 
    private $user = 'test'; 
    private $dbname = 'test'; 
    private $pass = 'test1'; 

    private $dbh; 
    private $error; 

    public function __construct(){ 
     // Set DSN 
     $dsn = 'mysql: host=' . $this->host . ';dbname=' . $this->dbname; 
     // Set options 
     $options = array(
      PDO::ATTR_PERSISTENT   => true, 
      PDO::ATTR_ERRMODE    => PDO::ERRMODE_EXCEPTION, 
      PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8' 
     ); 
     // Create a new PDO instanace 
     try{ 
      $this->dbh = new PDO($dsn, $this->user, $this->pass, $options); 
     } 
     // Catch any errors 
     catch(PDOException $e){ 
      $this->error = $e->getMessage(); 
      echo $this->error; 
      exit; 
     }  
    } 

    public function query($query){ 
     $this->stmt = $this->dbh->prepare($query); 
    } 
} 

我嘗試單獨我在不同的班級代碼,例如我得到它連接到一個clsUserController clsDBUser。我這樣做,所以我知道什麼類使用什麼數據庫代碼。我clsDBUser類看起來像這樣

class clsDBUser extends clsDatabase { 
    // construct 
    public function __construct() { 
     parent::__construct(); 
    } 

    // get users 
    public function getUsers($users_id){ 
     $query = " 
      SELECT 
       email 
      FROM 
       users 
      WHERE 
       users_id = :users_id 
     ";   
     $this->query($query); 
     $this->bind(':users_id', $users_id); 

     if($row = $this->single()){ 
      $this->close(); 
      return $row; 
     } 
     $this->close(); 
     return false;  
    } 
} 

我想知道如果這是去還是我現在創造了每類新的數據庫連接的方式嗎?因爲通常在PHP4中(是的,我知道老),我無法識別我每次都必須建立一個新的數據庫連接。

我需要改善嗎?我該如何改善這一點?

+0

觀察單例實現和其他設計模式,如工廠,或參見其他解決方案:http://stackoverflow.com/questions/2129162/how-do-you-efficiently-connect-to-mysql-in-php-without-重新連接數據庫 – Fky

+0

PDO已經有了一個非常好的類,爲什麼重複發生嚴重和不必要的輪子 – RiggsFolly

+0

爲什麼在所有操作都是「準備」時調用方法'query(**)**所有添加到PDO是混淆** – RiggsFolly

回答

0

mr.void的答案。總之:

  1. 擺脫clsDatabase。
  2. 創建一個PDO的實例。
  3. 將它傳遞到clsDBLogin的屬性,就像它顯示在mr.void的答案。
  4. 然後用這個PDO實例中的$形式這個 - > DB->準備()等

所以應該像

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

    public function validateLogin($email) 
    { 
     $email = trim($email); 

     // Check user in db to start verification 
     $query = 'SELECT * FROM users u, users_info ui 
        WHERE u.users_id = ui.users_id AND u.email = ?'; 
     $stmt = $this->db->prepare($query); 
     $stmt->execute([$email]); 
     return $stmt->fetch(); 
    } 
} 

$dsn = 'mysql: host=localhost;dbname=test;charset=utf8'; 
$options = array(
     PDO::ATTR_PERSISTENT   => true, 
     PDO::ATTR_ERRMODE    => PDO::ERRMODE_EXCEPTION, 
); 
// Create a new PDO instanace 
$pdo = new PDO($dsn, $this->user, $this->pass, $options); 

$DBLogin = new clsDBLogin($pdo); 
$user = $DBLogin->validateLogin($email); 
-1

只是不要從連接類(clsDatabase)擴展實體(clsDBUser)。

對於clsDatabase使用單身(或更高級的模式)。

例如:

class clsDatabase { 

    static private $instance = null; 

    // some other private fields 

    private function __construct(/* parameters*/) { 
     // do it 
    } 

    public static function instance() { 
     if (is_null(self::$instance)) { 
      self::$instance = new self(/* pass any parameters */); 
     } 
     return self::$instance; 
    } 

    public function queryRow($query) { 
     $oStatement = $this->dbh->prepare($query); 

     // ... 

     return $row; 
    } 
} 

class clsDBUser { 

    public function getUser($id) { 
     $query = "..."; 
     return $clsDatabase::instance()->queryRow($query); 
    } 

} 
+0

單身人士是一個反模式,你應該避免它。你想要的是DI(https://en.wikipedia.org/wiki/Dependency_injection)。你可以用php-di。它是一個DIC(依賴注入容器),可以自動連接你的依賴關係 –

+1

是的,DI是正確的*解決方案*,但是「不擴展」是正確的答案*。我寫了:「或更多的東西和先進的模式」。 –

+0

好,我可以用你的例子嗎?因爲我明天會試試這個,可能還有更多的問題回覆你,如果那是oké – poNgz0r

1

嘿,我會做這樣的事

class DB { 
    // connectionStuff goes Here 
} 

class Model { 
    private $db 

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

用途:

$db = new DB("your connection stuff goes here"); 


$model = new Model($db); 
$userModel = new UserModel($db); 
$anotherModel = new AnotherModel($db); 
1

重建:

clsDB類連接東西只有

class clsDB{ 
    // db settings 
    private $host = 'localhost'; 
    private $user = 'test'; 
    private $dbname = 'test'; 
    private $pass = 'test'; 

    private $dbh; 
    private $error; 

    public function __construct(){ 
     // Set DSN 
     $dsn = 'mysql: host=' . $this->host . ';dbname=' . $this->dbname; 
     // Set options 
     $options = array(
      PDO::ATTR_PERSISTENT   => true, 
      PDO::ATTR_ERRMODE    => PDO::ERRMODE_EXCEPTION, 
      PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8' 
     ); 
     // Create a new PDO instanace 
     try{ 
      $this->dbh = new PDO($dsn, $this->user, $this->pass, $options); 
     } 
     // Catch any errors 
     catch(PDOException $e){ 
      $this->error = $e->getMessage(); 
      echo $this->error; 
      exit; 
     }  
    }   
} 

clsDBLogin:

class clsDBLogin{ 
    private $db; 

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

在的index.php我做的:

$clsDB  = new clsDB(); 
$clsDBLogin = new clsDBLogin($clsDB); 

在clsDBLogin我會做:

您應該採取所示的道路
public function validateLogin($email){ 
    $email = str_replace(' ', '', $email); 
    $email = strtolower($email); 

    // Check user in db to start verification 
    $query = ' 
     SELECT 
      u.*, ui.* 
     FROM 
      users as u, 
      users_info as ui 
     WHERE 
      u.users_id = ui.users_id 
     AND 
      u.email = :email     
    '; 
    $this->db->prepare($query); 
    $this->db->bindValue(':email', $email, PDO::PARAM_STR); 

    if($this->db->execute()){ 
     if($row = $this->db->fetch(PDO::FETCH_ASSOC)){ 
      return $row;    
     }  
    } 
} 
+0

不完全。你有一個相當混亂的代碼(clsDatabase :: getInstance()遍佈整個地方),混淆(使用查詢作爲準備的別名,我稱之爲破壞)並且不靈活(這個代碼將堅持單個實例,而你將無法使用另一個)。此外,在關閉連接時,您將無法在腳本中運行多個查詢,這非常荒謬 –

+0

Oke,那麼要怎麼走呢? – poNgz0r

+0

1.擺脫clsDatabase。 2.創建一個PDO的實例。 3.將它傳遞到clrDBLogin的屬性,如mr.void的答案中所示。 4.然後以$ this-> db-> prepare()等形式使用這個pdo實例 –

0

有三層這裏:

  • 數據庫連接器:可以使用純PDO這個或數據庫抽象層庫(Doctrine DBAL
  • 實體存儲庫:換句話說,某種ORM。 Doctrine提供先進的ORM功能。當然,你可以編寫自己的輕量級解決方案。
  • 實體:可以是簡單的CRUDActiveRecord或邏輯記錄的任何其他對象表示。

當我們這樣做手工......首先,沒有擴展相互這些。一般:永遠不要從另一層擴展不同的層。改用Dependency Injection(DI)。

當您將所有特定信息(依賴關係)作爲構造函數參數傳遞時,這是一個非常簡單的DI案例。我的活動對象樣例Entity只是知道一個實體應該如何表現一般(在存儲庫中的鍵)。爲了簡單起見,我使用原始SQL。

庫類:

class Repository { 

    private $oPDO; 
    private $tableName; 
    private $keyFieldName; 

    public function __construct($oPDO, $tableName, $keyFieldName) { 
     $this->oPDO = $oPDO; 
     $this->tableName = $tableName; 
     $this->keyFieldName = $keyFieldName; 
    } 

    public function getPDO() { 
     return $this->oPDO; 
    } 

    public function getTableName() { 
     return $this->tableName; 
    } 

    public function getKeyFieldName() { 
     return $this->keyFieldName; 
    } 

    public function getEntity($id) { 
     return new Entity($this, $id); 
    } 

    public function createEntity() { 
     return new Entity($this, null); 
    } 

} 

實體類:

class Entity implements ArrayAccess { 

    private $oRepository; 
    private $id; 

    private $record = null; 

    public function __construct($oRepository, $id) { 
     $this->oRepository = $oRepository; 
     $this->id = $id; 
    } 

    public function load($reload = false) { 
     if (!$this->record && !$this->id) { 
      return false; 
     } 

     if (!$reload && !is_null($this->record)) { 
      return true; 
     } 

     $quotedTableName = $this->quoteIdentifier($this->oRepository->getTableName()); 
     $quotedKeyFieldName = $this->quoteIdentifier($this->oRepository->getKeyFieldName()); 
     $selectSql = "SELECT * FROM {$quotedTableName} WHERE {$quotedKeyFieldName} = ?"; 
     $oStatement = $this->oRepository->getPDO()->prepare($selectSql); 
     $this->bindParam($oStatement, 1, $this->id); 
     $oStatement->execute(); 

     $result = $oStatement->fetch(PDO::FETCH_ASSOC); 

     if ($result === false || is_null($result)) { 
      return false; 
     } 

     $this->record = $result; 
     return true; 
    } 

    public function save() { 
     $oPDO = $this->oRepository->getPDO(); 

     $tableName = $this->oRepository->getTableName(); 
     $keyFieldName = $this->oRepository->getKeyFieldName(); 
     $quotedTableName = $this->quoteIdentifier($tableName); 
     $quotedKeyFieldName = $this->quoteIdentifier($keyFieldName); 

     if (is_null($this->id)) { 
      $insertSql = "INSERT INTO {$quotedTableName} ("; 
      $insertSql .= implode(", ", array_map([$this, "quoteIdentifier"], array_keys($this->record))); 
      $insertSql .= ") VALUES ("; 
      $insertSql .= implode(", ", array_fill(0, count($this->record), "?")); 
      $insertSql .= ")"; 
      $oStatement = $oPDO->prepare($insertSql); 

      $p = 1; 
      foreach ($this->record as $fieldName => $value) { 
       $this->bindParam($oStatement, $p, $value); 
       $p++; 
      } 

      if ($oStatement->execute()) { 
       $this->id = $oPDO->lastInsertId(); 
       return true; 
      } else { 
       return false; 
      } 
     } else { 
      $updateSql = "UPDATE {$quotedTableName} SET "; 
      $updateSql .= implode(" = ?, ", array_map([$this, "quoteIdentifier"], array_keys($this->record))); 
      $updateSql .= " = ? WHERE {$quotedKeyFieldName} = ?"; 
      $oStatement = $oPDO->prepare($updateSql); 

      $p = 1; 
      foreach ($this->record as $fieldName => $value) { 
       $this->bindParam($oStatement, $p, $value); 
       $p++; 
      } 
      $this->bindParam($oStatement, $p, $this->id); 

      if ($oStatement->execute()) { 
       if (isset($this->record[$keyFieldName])) { 
        $this->id = $this->record[$keyFieldName]; 
       } 
       return true; 
      } else { 
       return false; 
      } 
     } 
    } 

    public function isExisting($reload = false) { 
     if (!$this->record && !$this->id) { 
      return false; 
     } 

     if (!$reload && !is_null($this->record)) { 
      return true; 
     } 

     $quotedTableName = $this->quoteIdentifier($this->oRepository->getTableName()); 
     $quotedKeyFieldName = $this->quoteIdentifier($this->oRepository->getKeyFieldName()); 
     $selectSql = "SELECT 1 FROM {$quotedTableName} WHERE {$quotedKeyFieldName} = ?"; 
     $oStatement = $this->oRepository->getPDO()->prepare($selectSql); 
     $oStatement->bindParam(1, $this->id); 
     $oStatement->execute(); 

     $result = $oStatement->fetch(PDO::FETCH_ASSOC); 

     if ($result === false || is_null($result)) { 
      return false; 
     } 

     return true; 
    } 

    public function getId() { 
     return $this->id; 
    } 

    public function getRecord() { 
     $this->load(); 
     return $this->record; 
    } 

    public function offsetExists($offset) { 
     $this->load(); 
     return isset($this->record[$offset]); 
    } 

    public function offsetGet($offset) { 
     $this->load(); 
     return $this->record[$offset]; 
    } 

    public function offsetSet($offset, $value) { 
     $this->load(); 
     $this->record[$offset] = $value; 
    } 

    public function offsetUnset($offset) { 
     $this->load(); 
     $this->record[$offset] = null; 
    } 

    private function quoteIdentifier($name) { 
     return "`" . str_replace("`", "``", $name) . "`"; 
    } 

    private function bindParam($oStatement, $key, $value) { 
     $oStatement->bindParam($key, $value); 
    } 

} 

用法:

$oRepo = new Repository($oPDO, "user", "user_id"); 

var_dump($oRepo->getEntity(2345235)->isExisting()); 

$oSameUser = $oRepo->getEntity(1); 
var_dump($oSameUser->isExisting()); 
var_dump($oSameUser->getRecord()); 

$oNewUser = $oRepo->createEntity(); 
$oNewUser["username"] = "smith.john"; 
$oNewUser["password"] = password_hash("ihatesingletons", PASSWORD_DEFAULT); 
$oNewUser["name"] = "John Smith"; 
$oNewUser->save(); 

$oNewUser["name"] = "John Jack Smith"; 
$oNewUser->save(); 

當然,Y您可以從RepositoryMoreConcreteEntity開始MoreConcreteRepositoryEntity以具體行爲。

相關問題