2017-02-08 59 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以具体行为。

相关问题