我在PHP中测试不同的MySQL连接方法时注意到了一些事情。
在PHP中建立数据库连接时,我经常使用odbc_connect()。我将odbc_connect()返回的资源变量保存到一个全局常量(使用define()函数),我可以在整个应用程序中方便地访问它。像这样:
使用odbc_connect()并将返回值保存为常量可以正常工作:
<?php
define("_conn", odbc_connect("Driver={MySQL ODBC 5.3 Unicode Driver};Database=MyDB;", "user", "pass"));
?>
将mysql_connect()(不推荐使用的)的返回值保存到常量中也可以正常工作:
<?php
define("_conn", mysql_connect("localhost", "user", "pass", "MyDB"));
?>
但是,尝试将mysqli_connect()的返回值保存为常量会 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返回RESOUCE(并且可以与define()函数一起使用)的唯一两个数据库连接函数是odbc_connect()和mysql_connect()(不推荐使用)。请看这个链接:http://php.net/manual/en/resource.php
有没有办法让mysqli_connect()返回一个RESOUCE,这样我就可以在常量中使用它的返回值(使用define()函数)?
PDO也不会返回RESOUCE。
答案 0 :(得分:2)
我建议在这种情况下使用单例模式 这是一个例子:
<?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();
答案 1 :(得分:0)
嗯,如您所见,PHP不允许存储non-scalar values in constants。
答案 2 :(得分:0)
在这种情况下,我肯定不会推荐单例模式,实际上,在一般情况下也是如此,因为它在很多情况下很难测试和扩展,并且不能用于同时处理多个连接,这可能是在某些时候需要。
单身模式只能让它变得容易全球化&#34;你的应用程序之间的连接,当然,因为,当时,那里有许多写得不好的PHP应用程序,它将开始每个脚本与新的连接导致许多重复的连接打开。 但实际上,使用全局直接在需要的对象上比使用单例更好地解决这个问题。当然,最好是实现某种依赖注入或注册模式来实现这一点,但是我认为这是一般的单例模式有多糟糕,尤其是在处理数据库时更是如此。
您甚至不需要实现自己的数据库处理程序,甚至不需要使用任何供应商,就像在Doktor OSwaldo example中完成一样,您可以从PDO获得所需的一切:
$db = new PDO('mysql:host=localhost;dbname=myDb', 'user', 'pass');
您可以将其包装到函数/方法中以在返回之前操作连接,甚至可以实现简约连接存储:
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时获取它)。这个例子仍然没有理想的可测试性(只是它的简单易于模拟),但它几乎就像在许多情况下一样。