2017-02-08 5 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); 
    } 
} 

Я пытаюсь отделить свой код в различных классах, например, я получил clsDBUser, который подключен к clsUserController. Я делаю это, поэтому я знаю, какой класс использует какой код базы данных. Мой класс 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- reconnecting-on-every-que – Fky

+0

PDO уже имеет отличный класс, зачем изобретать колесо плохо и без необходимости – RiggsFolly

+0

Зачем вызывать метод 'query()', когда все его выполнение - это 'подготовка' **, все, что вы добавляете к PDO это путаница ** – RiggsFolly

ответ

0

Вы должны взять дорогу показано ответ mr.void. Короче говоря:

  1. избавиться от clsDatabase.
  2. Создайте экземпляр PDO.
  3. передать его в собственность clsDBLogin, как показано в ответе mr.void.
  4. Затем используйте этот экземпляр PDO в виде $ this-> 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

Просто не расширяйте сущность (clsDBUser) от класса подключения (clsDatabase).

Используйте одноэлементный (или что-то более продвинутый рисунок) для 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

Rebuild:

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. передайте его в свойство clsDBLogin, как показано в ответе mr.void. 4. Затем используйте этот экземпляр pdo в виде $ this-> db-> prepare() и т. Д. –

0

Есть три слоя здесь:

  • базы данных разъема: вы можете использовать чистый PDO для этого или библиотеку абстракции базы данных слоя (Doctrine DBAL)
  • репозиторий юридических лиц: Другими словами, какой-то ОРМ. Doctrine обеспечивает расширенную функциональность ORM. Конечно, вы можете написать собственное облегченное решение.
  • объект: может быть простым CRUD, ActiveRecord или любым другим представлением объекта логической записи.

Когда мы делаем это вручную ... Сначала не распространяют эти друг от друга. Как правило: никогда не расширяйте другой слой от другого. Вместо этого используйте Dependency Injection (DI).

Это очень простой случай DI, когда вы передаете всю определенную информацию (зависимости) в качестве параметров конструктора. Мой активный объект-подобный пример Entity просто знает, как сущность должна вести себя вообще (у ключа в репозитории). Для простоты я использую raw SQL.

класс Repository:

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); 
    } 

} 

Entity Класс:

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(); 

Конечно, у ou может распространять MoreConcreteRepository от Repository и MoreConcreteEntity от Entity с определенным поведением.