PHP - 如何获得 mysqli_connect() 到 return 一个资源,以便它可以与 define() 一起使用

PHP - How to get mysqli_connect() to return a RESOURCE so it can be used with define()

我在 PHP 中测试不同的 MySQL 连接方法时注意到了一些事情。

在 PHP 中连接数据库时,我通常使用 odbc_connect()。我将 odbc_connect() return 的资源变量保存到一个全局常量中(使用 define() 函数),我可以在整个应用程序中方便地访问它。像这样:

使用 odbc_connect() 并将 return 值保存到常量中工作正常:

<?php
define("_conn", odbc_connect("Driver={MySQL ODBC 5.3 Unicode Driver};Database=MyDB;", "user", "pass"));
?>

将 mysql_connect()(已弃用的)的 return 值保存到常量中也可以正常工作:

<?php
define("_conn", mysql_connect("localhost", "user", "pass", "MyDB"));
?>

但是,尝试将 mysqli_connect() 的 return 值保存到常量中 NOT 工作:

<?php
define("_conn", mysqli_connect("localhost", "user", "pass", "MyDB"));
?>
Warning: Constants may only evaluate to scalar values in C:\...\script.php on line 164

这很不幸,因为使用 mysqli_connect() 建立连接并将句柄保存到常量中会很好,而 odbc_connect() 不可用。我做了研究,发现我可以与 MySQL 一起使用的唯一两个数据库连接函数是 return RESOUCE(并且可以与 define() 函数一起使用)是 odbc_connect()和 mysql_connect() (已弃用的)。看到这个link:http://php.net/manual/en/resource.php

有没有办法让 mysqli_connect() 变成 return 资源,这样我就可以在常量中使用它的 return 值(使用 define() 函数) ?

PDO 也不 return 资源。

嗯,如您所见,PHP 不允许存储 non-scalar values in constants

但您仍然可以实现Singleton pattern or Registry满足您的需求。

我建议在这种情况下使用单例模式 举个例子:

<?php
 class PDOConnection {

/**
 * singleton instance
 * 
 * @var PDOConnection 
 */
protected static $_instance = null;

/**
 * Returns singleton instance of PDOConnection
 * 
 * @return PDOConnection 
 */
public static function instance() {

    if ( !isset( self::$_instance ) ) {

        self::$_instance = new PDOConnection();

    }

    return self::$_instance;
}

/**
 * Hide constructor, protected so only subclasses and self can use
 */
protected function __construct() {}

function __destruct(){}

/**
 * Return a PDO connection using the dsn and credentials provided
 * 
 * @param string $dsn The DSN to the database
 * @param string $username Database username
 * @param string $password Database password
 * @return PDO connection to the database
 * @throws PDOException
 * @throws Exception
 */
public static function getConnection() {


    $dsn = 'mysql:dbname=_____;host=_____';
    $username = '_____';
    $password = '_____';

    $conn = null;
    try {

        $conn = new \PDO($dsn, $username, $password);

        //Set common attributes
        $conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

        return $conn;

    } catch (PDOException $e) {

        //TODO: flag to disable errors?


    }
    catch(Exception $e) {

        //TODO: flag to disable errors?


    }
}

/** PHP seems to need these stubbed to ensure true singleton **/
public function __clone()
{
    return false;
}
public function __wakeup()
{
    return false;
}
}

?>

那么您就可以在任何地方使用它了:

$dbh =  PDOConnection::getConnection();

我当然不会在这种情况下推荐单例模式,实际上,在一般情况下也是如此,因为它在许多情况下很难测试和扩展,并且不能用于一次处理多个连接,这在某些时候可能需要。

单例模式只会让 "globalise" 您的应用程序之间的连接变得容易,而且肯定会出名,因为在当时,许多 php 应用程序编写得不好,每个脚本都会开始使用新连接导致打开许多重复连接。 但实际上,在需要的地方直接在对象上使用全局比使用单例更好地解决这个问题。当然,最好实现某种依赖注入或注册表模式来这样做,但我认为这就是一般的单例模式的糟糕程度,尤其是在处理 db 时更是如此。

而且您甚至不需要实现自己的数据库处理程序,甚至不需要使用任何供应商的处理程序,就像在 中所做的那样,您可以直接从 PDO 获得所需的一切:

$db = new PDO('mysql:host=localhost;dbname=myDb', 'user', 'pass');

您可以将其包装到 function/method 中,以便在 return 之前操纵连接,甚至可以实现简约的连接存储:

function getConnection($which= 'default') {
    static $connections = [
        // connectionName => connectionOptions
        'default' => [
            'dsn'  => 'mysql:host=localhost;dbname=myDb',
            'user' => 'user',
            'pass' => 'pass',
            // 'option' => value,
            // ...
        ],
        // ...
    ], $dbStore = [];

    if (isset($dbStore[$which])) {
        return $dbStore[$which];
    }

    if (!isset($connections[$which])) {
        throw new \Exception("DB setup not supported");
    }

    $dbStore[$which] = new \PDO($connections[$which]['dsn'], $connections[$which]['user'], $connections[$which]['pass']);

    // eventually set some options that could be stored in $connections[$which]
    // $dbStore[$which]->setAttribute( ...

    return $dbStore[$which];
}

这将提供与单例相同的易用性和防止重复连接的保证,但仍然允许您一次使用多个连接:

// get default connection
$defaultDb = getConnection();

// get another connection
$anotherDb = getConnection('another');

当然,您最好将连接选项存储在某种配置中(例如,在第一次调用 getConnection 时获取它)。而且这个例子仍然不是理想的可测试的(只是它的简单性使其易于模拟),但它几乎可以满足许多情况。