PHP OOP-将DB类注入另一个类的构造方法

PHP OOP-将DB类注入另一个类的构造方法,php,Php,我有一个连接数据库的类 <?php require_once('config.php'); class Database { function __construct(){ $this->connect(); } public function connect(){ $this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE); } }

我有一个连接数据库的

 <?php

require_once('config.php');

class Database {

   function __construct(){
     $this->connect();
   }

   public function connect(){
     $this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE);
   }

}

 ?>
但这不起作用,因为对于仍然在主类中的查询,我得到了一个错误,我打算稍后将它们移动到DB类中。但现在我得到了一个错误:

致命错误:未捕获错误:调用未定义的方法 /home/vagrant/Projects/MyProject/index.php中的数据库::query() 在线262

查询在主类中完成:

$result = $this->mysqli->query( "SELECT shops.*, shops.id AS shop,SUM(price)...

您正在尝试调用
数据库
类上的
query()
方法。虽然该类在其
$connection
属性中包含
mysqli
对象,但它不公开该
mysqli
对象的
query()
方法

给定当前的代码,您可以进一步深入对象结构,直接在
mysqli
上调用
query()
,但这很麻烦

// Call the query() method directly on the connection
$result = $this->mysqli->connection->query( "SELECT shops.*, shops.id AS shop,SUM(price)...
我不喜欢这种方法,因为它要求您的类比它们可能应该知道的更多地了解
数据库的内部工作。它把他们结合得太紧密了

或者,您可以在
数据库
类中创建一个
query()
方法,将
mysqli
对象的必要功能封装在其中

class Database {

   function __construct(){
     $this->connect();
   }

   public function connect(){
     $this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE);
   }

   // Expose a query() method that calles the inner mysqli's query
   public function query($sql) {
     return $this->connection->query($sql);
   }
}
这将允许您打包更多功能,例如在一个方法调用中查询和获取所有结果行:

class Database {
   //....

   // A more featured query() that returns the
   // rows as an array
   public function query($sql) {
     $result = $this->connection->query($sql);
     while ($row = $result->fetch_assoc()) {
        $rows[] = $row;
     }
     // Return an array of all the rows fetched from the query
     return $rows;
   }
}
如果您这样做,您应该能够像最初尝试的那样调用
$this->mysqli->query(“…”)
,或者使用简单版本获取结果资源,之后您必须自己获取代码,或者在更具特色的版本中获取关联结果行数组

但是,创建这些类型的数据库包装类可能会很快变得笨拙。仔细考虑希望向应用程序中的其他类公开
mysqli
对象的哪些方面。在
数据库
类中包装每个
mysqli
方法不是一个好主意。此时,
数据库
类的实用性大大降低,您也可以直接传入一个
mysqli
对象。如果您没有主动向
mysqli
添加功能,那么创建另一个封装它的类就没有什么意义了

关于
var$mysqli的注释。。。这是一个旧的不推荐使用的类属性语法。
var
关键字是PHP4的残余,现在不鼓励使用它。事实上,它已经从最近的PHP版本中删除。相反,您应该通过PHP5+语法声明它:

// Declare as a public property
public $mysqli;

// Or better, as a private (or protected) property so it cannot
// be accessed outside the Main class' own methods
private $mysqli;
在你的问题标题中,你提到了注射。您的类现在没有这样做,但是最好提前实例化
数据库
,并将其注入需要它的类构造函数中

class Main{

    public $mysqli;

    // Pass a database as a constructor param
    public function __construct($database){
        $this->mysqli = $database;
    }
然后将其实例化为:

$db = new Database();
// Pass the $db to the other classes
$main = new Main($db);

重要的是,这将防止您为实例化的
Main
的每个对象以及以相同方式构造的任何其他类打开单独的数据库连接。这样做可以快速使用服务器可用的MySQL连接。

以$this->mysqli->query()的形式访问查询函数;我们在这里看不到
query
的用法,因此我们无法帮助您在数据库类中调用
query()
必须为
$this->connection->query()
,除非您编写一个
query()
方法将其直接包装到
Database
类中。请将代码张贴在您试图调用
query()
@MichaelBerkowski的位置。我已将查询添加到question@Leff好的,我充实了一个答案。@Leff这有意义吗?非常可靠的答案!我会使用
private$mysqli
而不是
public
,因此您不能从对象外部访问属性以强制松耦合+1尽管@ʰᵈˑ我同意,但不想引入太多的概念或太多地改变OP的原始方法。我再补充一点。
$db = new Database();
// Pass the $db to the other classes
$main = new Main($db);