仅在需要时自动连接到PDO

时间:2011-03-30 09:57:35

标签: php mysql database pdo

我有一段代码,根据请求的URL,将包含十四个其他文件中的一个。这14个文件中的一些需要连接到三个不同数据库中的一个,并且可以随时添加其他文件。

我不希望默认情况下将PDO连接打开到所有三个数据库,因为它浪费资源并且会缩短执行时间。所以我的想法是将所有SQL查询包装在一个函数中。第一次在非开放PDO连接上执行查询时,try {}错误处理程序可以捕获它,找出问题所在(在这种情况下连接不存在),然后打开连接并重新执行查询。这样,数据库只在需要时连接 - 只要连接字符串(主机,数据库,用户名,密码)都是事先定义的,我就看不到它工作中的任何问题。

但是,我需要继续使用它,并且大约7天内无法访问开发框,所以任何人都可以看到该方案有任何问题吗?此外,任何人都可以给我一个错误信息,如果没有打开连接,处理程序 - > errorInfo()将返回?

5 个答案:

答案 0 :(得分:12)

准确使用此类,如何使用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.
}

答案 1 :(得分:5)

这是正确的想法,但不是最好的实现。

包装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个单独的Wrapper课程。将所有内容放入一个类是可行的(三个不同的$db变量),但可能比它的价值更令人困惑。

答案 2 :(得分:5)

我使用__call魔术方法采用了另一种方法,因此您不需要为每个方法创建单独的包装器。

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

您只需要用PDOLazyConnector替换PDO实例,所以:

$dbh = new PDO($dsn, $user, $password, $driver_options);

使用:

$dbh = new PDOLazyConnector($dsn, $user, $password, $driver_options);

答案 3 :(得分:1)

PDO有一个持久连接选项 PDO :: ATTR_PERSISTENT

请参阅http://php.net/manual/en/book.pdo.php

中的评论

答案 4 :(得分:0)

function &get_pdo()
{
    static $_PDO = null;

    if ($_PDO === null)
    {
        $_PDO = new PDO('your DSN', 'username', 'password');
    }

    return $_PDO;
}

然后你就做了

$stmt = get_pdo()->prepare('...');

您可以通过扩展PDO类并向其添加静态单例函数来执行相同的操作。我发现这种方法比较简单。还让您有机会从堆栈中的任何位置调用它,而无需将您的连接放在参数中(根据具体情况,这可能是好的还是坏的。)