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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 对接wps接口实现获取元数据
  • ¥20 给自己本科IT专业毕业的妹m找个实习工作
  • ¥15 用友U8:向一个无法连接的网络尝试了一个套接字操作,如何解决?
  • ¥30 我的代码按理说完成了模型的搭建、训练、验证测试等工作(标签-网络|关键词-变化检测)
  • ¥50 mac mini外接显示器 画质字体模糊
  • ¥15 TLS1.2协议通信解密
  • ¥40 图书信息管理系统程序编写
  • ¥20 Qcustomplot缩小曲线形状问题
  • ¥15 企业资源规划ERP沙盘模拟
  • ¥15 树莓派控制机械臂传输命令报错,显示摄像头不存在