duanfu5239
2017-04-26 21:09
浏览 44
已采纳

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

This is in reference to a CentOS 7 server running PHP 5.4 and MariaDB 5.5.

I am somewhat new to OOP in PHP. In converting a bunch of scripts from MySQL to MySQLi and from procedural database functions to OOP, I set up this basic Database class:

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

With the former procedural database functions that used mysql_*, a persistent database connection was made near the start of the script and the resource ID was stored in a global variable, then all queries were run through that one database connection by accessing the global resource variable. Importantly, this worked well from within other functions and objects. Here's how that function worked:

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

So at the start of each script I'd do this...

db_connect(); 

And then run my queries like this...

$result = mysql_query($query, db_connect());

This made sure one database connection was made and that all queries are run through that connection.

With the above new Database class, I instantiate it at the start of my script...

$db = new Database;
$db->connect();

But I don't understand how to make that Database object accessible to other objects that need to perform database queries so that the same database connection is used by the entire script. What I do now is essentially this...

class MyClass
{
    public function myFunction() 
    {
        $db = new Database; 
        $data = $db->select("SELECT * FROM mydata WHERE id = 888");
        ...
    }
}

This instantiates a new Database object within the above class, which is creating a new and additional connection to the database, because it can't access the Database $db object created in the parent calling script (that I know of).

Is there a way to use an object to open a persistent MySLQi database connection that all functions and objects loaded by that script can use? Or is this just something that is better done with a procedural function rather than a class and object? Does the solution lie in making the Database properties and its methods static? If I do that, I'm not sure how I load the database username and password from the config.ini file which the connect() function needs and is only done upon instantiation of the Database object.

I guess the basic question here is how do I access the properties or methods in an instantiated object from another object? Or maybe that isn't the question and I'm completely missing something else. Thanks!

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • dongxian8272 2017-04-26 21:21
    已采纳

    There are a few options, one simple one (and likely the preferred) would be to use a static factory method in your database class that returns a previously initialized instance of the database class.

    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
    }
    

    This static method can be called from anywhere in any context and would allow for getting the same connected instance of the database. Just call $db = Database::getDB() anywhere you need it. For example:

    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();
    

    Another option, and one that I use for simplicity, is declare your connection static and reference that everywhere in your database class for queries and such. This allows for creating $db = new Database() anywhere and will just use the same connection. I've had this frowned upon as if it were same as a global because you can really only connect to one database (subsequent connections would overwrite the connection variable) But it worked for me and I didn't need multiple connections. I also like it that I can have each instance remember whatever queries were run on that instance and have a private count of the queries run.

    打赏 评论
  • dongliao4353 2017-04-26 21:30

    You can do something like that a static method with a only a single tone

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

    and to make a connection to the database and make a query simple use the lines:

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

相关推荐 更多相似问题