Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/250.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 仅在需要时自动连接到PDO_Php_Mysql_Database_Pdo - Fatal编程技术网

Php 仅在需要时自动连接到PDO

Php 仅在需要时自动连接到PDO,php,mysql,database,pdo,Php,Mysql,Database,Pdo,我有一段代码,根据请求的URL,它将包括14个其他文件中的一个。这十四个文件中的一些需要连接到三个不同数据库中的一个,并且可以随时添加其他文件 我不想在默认情况下打开所有三个数据库的PDO连接,因为这会浪费资源,并且会减慢执行时间。因此,我的想法是将所有SQL查询封装在一个函数中。第一次在未打开的PDO连接上执行查询时,try{}错误处理程序可以捕获它,找出问题所在(在本例中,连接不存在),然后打开连接并重新执行查询。这样,数据库只在需要时才被连接到—只要连接字符串(主机、数据库、用户名、密码)

我有一段代码,根据请求的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('...');