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

Нужно ли мне это улучшать, как мне это нужно улучшить?

Solutions Collecting From Web of "Использовать класс базы данных PDO без создания нового подключения каждый раз?"

Вы должны пройти по дороге, указанной в ответе mr.void. Вкратце:

  1. избавиться от clsDatabase.
  2. Создайте экземпляр PDO.
  3. передайте его в свойство clsDBLogin, как показано в ответе mr.void.
  4. Затем используйте этот экземпляр pdo в виде $ this-> db-> prepare () и т. Д.

Так что это должно быть

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

Эй, я бы сделал что-то вроде этого

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

Перестройка:

Класс 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; } } } 

Здесь есть три слоя:

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

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

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

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

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

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