Php 仅在需要时自动连接到PDO
我有一段代码,根据请求的URL,它将包括14个其他文件中的一个。这十四个文件中的一些需要连接到三个不同数据库中的一个,并且可以随时添加其他文件 我不想在默认情况下打开所有三个数据库的PDO连接,因为这会浪费资源,并且会减慢执行时间。因此,我的想法是将所有SQL查询封装在一个函数中。第一次在未打开的PDO连接上执行查询时,try{}错误处理程序可以捕获它,找出问题所在(在本例中,连接不存在),然后打开连接并重新执行查询。这样,数据库只在需要时才被连接到—只要连接字符串(主机、数据库、用户名、密码)都是预先定义的,我就看不出它有任何问题Php 仅在需要时自动连接到PDO,php,mysql,database,pdo,Php,Mysql,Database,Pdo,我有一段代码,根据请求的URL,它将包括14个其他文件中的一个。这十四个文件中的一些需要连接到三个不同数据库中的一个,并且可以随时添加其他文件 我不想在默认情况下打开所有三个数据库的PDO连接,因为这会浪费资源,并且会减慢执行时间。因此,我的想法是将所有SQL查询封装在一个函数中。第一次在未打开的PDO连接上执行查询时,try{}错误处理程序可以捕获它,找出问题所在(在本例中,连接不存在),然后打开连接并重新执行查询。这样,数据库只在需要时才被连接到—只要连接字符串(主机、数据库、用户名、密码)
然而,我需要继续推进这个过程,并且在大约7天内无法访问dev box,所以有人能看到这个场景有任何问题吗?另外,有人能告诉我如果连接未打开,handler->errorInfo()将返回的错误消息吗?使用这个类时,您将使用
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.
}
PDO有一个持久连接选项PDO::ATTR_persistent
请参见中的注释这是正确的想法,但不是最佳的实施方案 包装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;
}
}
这有很多好处:
- 允许您在逻辑上将SQL操作分组到一个(或多个!)类中
- 如果不需要,则不连接到数据库
- 不依赖(脆性)错误检查来正常工作
在您的特定情况下,您可能应该使用3个独立的
包装类。将所有内容放在一个类中是可行的(三个不同的$db
变量),但可能比它的价值更让人困惑。我采用了另一种方法,使用了u 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);
与:
那你就这么做吧
$stmt = get_pdo()->prepare('...');
您也可以通过扩展PDO类并向其添加静态单例函数来实现这一点。我发现这种方法更简单。您还可以从堆栈上的任何位置调用它,而无需将连接放入参数中(根据具体情况,参数可以是好的,也可以是坏的)。最好的方法。PDO应该被扩展。当然,您会返回重载方法的结果。除此之外,;正确的回答!嗨,伙计们,哇-没想到这么快就能得到答案!!克里斯/乔恩,非常感谢你的回答。这可能是我,厚-没有评论请但根据Chris的回答,我看不出它如何决定连接三个数据库中的哪一个?还是我遗漏了什么。PDO对我来说是很新的,但似乎是合乎逻辑的!我发现编写一个不直接扩展PDO,而是将其用作对象参数(即,$this->db=new PDO()
)的包装器会更舒服。这样,我可以(1)编写更易于使用的与DB交互的接口,并且(2)可以将DB扩展从PDO更改为其他内容,并且如果需要,可以毫无问题地继续使用我的包装器。@TIW,您将有3个对象(例如,$db1
,$db2
和$db3
),每个对象都是用不同的参数创建的(主机、端口、用户、pswd).嗨,伙计们,哇-没想到这么快就能得到答案!!Chris/Jon,非常感谢你的回答。我认为你不能在PDO中使用变量?我的想法是在查询中传递数据库名称,然后根据需要获取处理连接的代码-只要连接字符串是预定义的。这将是n避免使用三个单独的包装器类-但我认为这不起作用…是吗?谢谢你的例子,我认为这是我前进的方向。还必须说谢谢-我以前从未理解过私有函数…你的例子向我展示了如何使用它们!@TIW,关于私有成员-还有受保护的成员;)虽然私有成员只能在定义它们的类中使用,但受保护成员也可以在子类中使用,即,在扩展定义受保护成员的类的类中。我建议告诉PDO在发生错误时抛出异常,而不是依赖errorInfo
。在连接选项中,使用数组(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION)
@Chris,视情况而定。若应用程序通常不使用异常,那个么在PDO中启用它们将弊大于利。
function &get_pdo()
{
static $_PDO = null;
if ($_PDO === null)
{
$_PDO = new PDO('your DSN', 'username', 'password');
}
return $_PDO;
}
$stmt = get_pdo()->prepare('...');