У меня есть раздел кода, который в зависимости от запрошенного URL будет содержать один из четырнадцати других файлов. Некоторые из этих четырнадцати файлов требуют подключения к одной из трех разных баз данных, а дополнительные файлы могут быть добавлены в любое время.
Я не хочу открывать соединения PDO по умолчанию для всех трех баз данных, поскольку это пустая трата ресурсов и замедлит время выполнения. Поэтому моя мысль состоит в том, чтобы обернуть все SQL-запросы внутри функции. В первый раз, когда запрос выполняется в незащищенном PDO-соединении, обработчик ошибок try {} может его поймать, выяснить, в чем проблема (в этом случае соединение не существует), затем откройте соединение и заново выполните запрос. Таким образом, база данных подключается только по мере необходимости – пока все строки подключения (хост, база данных, имя пользователя, пароль) определены заранее, я не вижу никаких проблем в работе.
Тем не менее, мне нужно продолжать с этим и не иметь доступа к блоку dev около 7 дней, так что может ли кто-нибудь увидеть какие-либо проблемы с этим сценарием? Кроме того, может ли кто-нибудь сообщить мне сообщение об ошибке, что обработчик-> errorInfo () вернется, если соединение не будет открыто?
Это правильная идея, но не лучшая ее реализация.
Обход операций SQL хорош. Но почему бы вам не сделать так:
class Wrapper { private static $db; public static function someQuery() { $db = self::getDatabase(); // now go on to execute the query } private static function getDatabase() { if (self::$db === null) { self::$db = // connect here } return self::$db; } }
Это имеет много преимуществ:
В вашем конкретном случае вы, вероятно, должны пойти с 3 отдельными классами Wrapper
. Включение всего в один класс выполнимо (три разные переменные $db
), но, вероятно, более запутанное, чем того стоит.
Используйте этот класс именно так, как вы бы использовали класс PDO
.
class DB extends PDO { protected $_config = array(); protected $_connected = false; public function __construct($dsn, $user = null, $pass = null, $options = null) { //Save connection details for later $this->_config = array( 'dsn' => $dsn, 'user' => $user, 'pass' => $pass, 'options' => $options ); } public function checkConnection() { if (!$this->_connected) { extract($this->_config); parent::__construct($dsn, $user, $pass, $options) $this->_connected = true; } } public function query($query) { $this->checkConnection(); return parent::query($query); } public function exec($query) { $this->checkConnection(); return parent::exec($query); } //etc. }
Я использовал другой подход, используя метод __call magic, поэтому вам не нужно создавать отдельные обертки для каждого метода.
class PDOLazyConnector { private $dsn; private $username; private $password; private $driver_options; private $dbh; public function __construct ($dsn, $username, $password, $driver_options = array ()) { $this->dsn = $dsn; $this->username = $username; $this->password = $password; $this->driver_options = $driver_options; } public function __call ($function, $args) { // connect to db (first time only) $this->__init_dbh (); // invoke the original method return call_user_func_array (array($this->dbh, $function), $args); } public function __get ($property) { return $this->dbh->$property; } private function __init_dbh () { // If db handler is not open yet, do it now if (empty ($this->dbh)) { $this->dbh = new PDO ($this->dsn, $this->username, $this->password, $this->driver_options); } } }
Вам просто нужно заменить свое PDO-инстанцию на PDOLazyConnector, так что:
$dbh = new PDO($dsn, $user, $password, $driver_options);
с:
$dbh = new PDOLazyConnector($dsn, $user, $password, $driver_options);
PDO имеет возможность для постоянных соединений PDO :: ATTR_PERSISTENT .
См. Комментарии в http://php.net/manual/en/book.pdo.php
function &get_pdo() { static $_PDO = null; if ($_PDO === null) { $_PDO = new PDO('your DSN', 'username', 'password'); } return $_PDO; }
Тогда вы просто делаете
$stmt = get_pdo()->prepare('...');
Вы можете сделать то же самое, расширив класс PDO и добавив к нему статическую одноэлементную функцию. Я считаю этот подход более простым. Также дает вам возможность вызывать его из любого места в стеке, не ставя его в аргументы (что может быть хорошим или плохим, в зависимости от ситуации).