使用PHP中其他对象的持久数据库对象连接

时间:2017-04-26 21:09:30

标签: php oop mysqli

这是指运行PHP 5.4和MariaDB 5.5的CentOS 7服务器。

我对PHP中的OOP有些新意。在将一堆脚本从MySQL转换为MySQLi以及从过程数据库函数转换为OOP时,我设置了这个基本的数据库类:

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

这会在上面的类中实例化一个新的Database对象,它正在创建一个新的和额外的数据库连接,因为它无法访问在父调用脚本中创建的Database $db对象(我知道)的)。

有没有办法使用对象打开一个持久的MySLQi数据库连接,该脚本加载的所有函数和对象都可以使用?或者这是使用过程函数而不是类和对象更好地完成的事情?解决方案是否在于使数据库属性及其方法静态?如果我这样做,我不确定如何从connect()函数需要的config.ini文件加载数据库用户名和密码,并且仅在实例化Database对象时完成。

我想这里的基本问题是如何从另一个对象访问实例化对象中的属性或方法?或许这不是问题,我完全错过了其他的东西。谢谢!

2 个答案:

答案 0 :(得分:3)

你可以做一些只有一个音调的静态方法

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

并建立与数据库的连接并简单地使用以下行:

$db = Database::getInstance();
$mysqli = $db->getConnection(); 
$sql_query = "SELECT foo FROM .....";
$result = $mysqli->query($sql_query);

答案 1 :(得分:0)

有一些选项,一个简单的选项(可能是首选的)将在数据库类中使用静态工厂方法,该方法返回先前初始化的数据库类实例。

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(),并且只使用相同的连接。我对此感到厌倦,好像它与全局一样,因为你真的只能连接到一个数据库(后续连接会覆盖连接变量)但它对我有用,我不需要多个连接。我也喜欢它,我可以让每个实例记住在该实例上运行的任何查询,并且运行查询的私有计数。