在PHP中使用来自其他对象的持久数据库对象连接
这是指运行PHP5.4和MARIADB5.5的CentOS 7服务器 我对PHP中的OOP有些陌生。在将一系列脚本从MySQL转换为MySQLi以及从过程数据库函数转换为OOP的过程中,我设置了以下基本数据库类:在PHP中使用来自其他对象的持久数据库对象连接,php,oop,mysqli,Php,Oop,Mysqli,这是指运行PHP5.4和MARIADB5.5的CentOS 7服务器 我对PHP中的OOP有些陌生。在将一系列脚本从MySQL转换为MySQLi以及从过程数据库函数转换为OOP的过程中,我设置了以下基本数据库类: class Database { private $host = "localhost"; private $username; private $password; private $database; private $dbconnect;
class Database
{
private $host = "localhost";
private $username;
private $password;
private $database;
private $dbconnect;
function __construct()
{
// Load config file for database connection info
$ini = parse_ini_file("config.ini");
$this->username = $ini['db.user'];
$this->password = $ini['db.pword'];
$this->database = $ini['db'];
}
public function connect()
{
// Only make a new connection if one not already established.
if (empty($this->dbconnect)) {
$mysql = new mysqli($this->host, $this->username, $this->password, $this->database);
if ($mysql->connect_errno) {
throw new appError($mysql->connect_error);
}
$this->dbconnect = $mysql;
}
return $this->dbconnect;
}
public function query($query)
{
$db = $this->connect();
$result = $db->query($query);
if ($db->errno) return false;
return $result;
}
public function select($query)
{
$rows = array();
$result = $this->query($query);
if ($result === false) return false;
// Create array with results
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
return $rows;
}
}
对于以前使用mysql_*的过程数据库函数,在脚本开始附近建立持久数据库连接,并将资源ID存储在全局变量中,然后通过访问全局资源变量通过该数据库连接运行所有查询。重要的是,这在其他函数和对象中运行良好。下面是该函数的工作原理:
function db_connect() {
if (!empty($GLOBALS['DBCONNECT']) && is_resource($GLOBALS['DBCONNECT'])) {
return $GLOBALS['DBCONNECT'];
} else {
$result = mysql_connect("localhost", DB_USER, DB_PASSWORD);
$GLOBALS['DBCONNECT'] = $result;
return $result;
}
}
所以在每个脚本的开始我都会这样做
db_connect();
然后像这样运行我的查询
$result = mysql_query($query, db_connect());
这确保建立了一个数据库连接,并且所有查询都通过该连接运行
使用上面的新数据库类,我在脚本开始时实例化它
$db = new Database;
$db->connect();
但我不明白如何使需要执行数据库查询的其他对象可以访问该数据库对象,以便整个脚本使用相同的数据库连接。我现在做的基本上是
class MyClass
{
public function myFunction()
{
$db = new Database;
$data = $db->select("SELECT * FROM mydata WHERE id = 888");
...
}
}
这在上面的类中实例化了一个新的数据库对象,它正在创建一个新的和附加的数据库连接,因为它无法访问在父调用脚本(我知道)中创建的数据库$db
对象
有没有一种方法可以使用一个对象来打开一个持久的MySLQi数据库连接,该脚本加载的所有函数和对象都可以使用?或者这只是一个过程函数而不是类和对象更好地完成的事情?解决方案是否在于使数据库属性及其方法成为静态的?如果这样做,我不确定如何从config.ini文件加载数据库用户名和密码,connect()
函数需要该文件,并且仅在实例化数据库对象时才加载
我想这里的基本问题是如何从另一个对象访问实例化对象中的属性或方法?也许这不是问题所在,我完全错过了其他的东西。谢谢 有几个选项,一个简单的选项(可能是首选)是在数据库类中使用静态工厂方法,该方法返回数据库类以前初始化的实例
class Database
{
//static instance of the class
private static $instance;
public static function getDB()
{
//if the instance is not set, set it
if(is_null(self::$instance))
{
self::$instance = new Database();
self::$instance->connect();
}
return self::$instance;
}
//rest of your class below
}
此静态方法可以从任何上下文中的任何位置调用,并允许获取相同的数据库连接实例。只要在任何需要的地方调用$db=Database::getDB()
。例如:
function TestFunction()
{
//get an instance to the database
$dbInstance = Database::getDB();
//then use the database object like you normally would.
$dbInstance->query("SELECT * FROM `someTable`");
}
class TestClass
{
public function doSomething()
{
//get an instance to the database
$dbInstance = Database::getDB();
//then use the database object like you normally would.
$dbInstance->query("SELECT * FROM `someTable`");
}
}
$tc = new TestClass();
$tc->doSomething();
另一个选项,也是为了简单起见,我使用的一个,是声明您的连接为静态的,并引用数据库类中任何地方的查询等。这允许在任何地方创建
$db=new Database()
,并且只使用相同的连接。我一直不赞成它,因为它就像一个全局数据库一样,因为您实际上只能连接到一个数据库(后续连接将覆盖连接变量),但它对我有效,我不需要多个连接。我还喜欢让每个实例记住在该实例上运行的任何查询,并对运行的查询进行私有计数。有几个选项,一个简单的选项(可能是首选选项)将是在数据库类中使用静态工厂方法,该方法返回数据库类以前初始化的实例
class Database
{
//static instance of the class
private static $instance;
public static function getDB()
{
//if the instance is not set, set it
if(is_null(self::$instance))
{
self::$instance = new Database();
self::$instance->connect();
}
return self::$instance;
}
//rest of your class below
}
此静态方法可以从任何上下文中的任何位置调用,并允许获取相同的数据库连接实例。只要在任何需要的地方调用$db=Database::getDB()
。例如:
function TestFunction()
{
//get an instance to the database
$dbInstance = Database::getDB();
//then use the database object like you normally would.
$dbInstance->query("SELECT * FROM `someTable`");
}
class TestClass
{
public function doSomething()
{
//get an instance to the database
$dbInstance = Database::getDB();
//then use the database object like you normally would.
$dbInstance->query("SELECT * FROM `someTable`");
}
}
$tc = new TestClass();
$tc->doSomething();
另一个选项,也是为了简单起见,我使用的一个,是声明您的连接为静态的,并引用数据库类中任何地方的查询等。这允许在任何地方创建
$db=new Database()
,并且只使用相同的连接。我一直不赞成它,因为它就像一个全局数据库一样,因为您实际上只能连接到一个数据库(后续连接将覆盖连接变量),但它对我有效,我不需要多个连接。我还喜欢这样,我可以让每个实例记住在该实例上运行的任何查询,并对运行的查询进行私有计数。您可以使用一个静态方法,只需一个音调
<?php
/*
* Mysql database class - only one connection alowed
*/
class Database {
private $_connection;
private static $_instance; //The single instance
private $_host = "HOSTt";
private $_username = "USERNAME";
private $_password = "PASSWORd";
private $_database = "DATABASE";
/*
Get an instance of the Database
@return Instance
*/
public static function getInstance() {
if(!self::$_instance) { // If no instance then make one
self::$_instance = new self();
}
return self::$_instance;
}
// Constructor
private function __construct() {
$this->_connection = new mysqli($this->_host, $this->_username,
$this->_password, $this->_database);
// Error handling
if(mysqli_connect_error()) {
trigger_error("Failed to conencto to MySQL: " . mysql_connect_error(),
E_USER_ERROR);
}
}
// Magic method clone is empty to prevent duplication of connection
private function __clone() { }
// Get mysqli connection
public function getConnection() {
return $this->_connection;
}
}
你可以用一个静态的方法,只需一个音调就可以做到这一点
<?php
/*
* Mysql database class - only one connection alowed
*/
class Database {
private $_connection;
private static $_instance; //The single instance
private $_host = "HOSTt";
private $_username = "USERNAME";
private $_password = "PASSWORd";
private $_database = "DATABASE";
/*
Get an instance of the Database
@return Instance
*/
public static function getInstance() {
if(!self::$_instance) { // If no instance then make one
self::$_instance = new self();
}
return self::$_instance;
}
// Constructor
private function __construct() {
$this->_connection = new mysqli($this->_host, $this->_username,
$this->_password, $this->_database);
// Error handling
if(mysqli_connect_error()) {
trigger_error("Failed to conencto to MySQL: " . mysql_connect_error(),
E_USER_ERROR);
}
}
// Magic method clone is empty to prevent duplication of connection
private function __clone() { }
// Get mysqli connection
public function getConnection() {
return $this->_connection;
}
}
不要使用static@getl0st很高兴看到这个评论背后的原因。如果使用得当,静态并不都是坏事。一个工厂方法,一个被广泛接受的实践,非常需要它。另外,我看不到你的替代方案。您喜欢全局方法吗?如何从需要执行数据库查询的另一个对象中访问getDB()方法,以及如何处理它?由于
getDB
方法是静态的,因此它在基类上全局可用。您可以在需要数据库类实例的任何位置使用Database::getDB()
。这将返回类的一个实例,剩下的大部分代码都是相同的。我将更新答案,这是一个如何使用该函数的示例。@JonathanKuhn感谢您澄清您的答案。我还对您提到的另一个选项感到好奇,即从静态连接开始。在上面的类中,我是否只需在属性中使用private static$dbconnect
,然后在connect()
函数中将其引用为self::$dbconnect
?显然,我对静态属性和方法理解不够。不要使用static@getl0st很高兴看到这个评论背后的原因。如果使用得当,静态并不都是坏事。一个工厂方法,一个被广泛接受的实践,非常需要它。另外,我看不到你的替代方案。沃