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

时间:2017-03-29 20:00:56

标签: php

我有一个Database类用于连接数据库。

 <?php

require_once('config.php');

class Database {

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

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

}

 ?>

我需要使用数据库连接的主类:

include 'includes/database.php';

class Main{

    var $mysqli;

    public function __construct(){
        $this->mysqli = new Database();
    }

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

  

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

查询在Main类中完成:

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

1 个答案:

答案 0 :(得分:1)

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

根据您当前的代码,您可以深入钻取对象结构,直接在query()上调用mysqli,但这很麻烦。

// Call the query() method directly on the connection
$result = $this->mysqli->connection->query( "SELECT shops.*, shops.id AS shop,SUM(price)...

我不喜欢这种方法,因为它要求你的课程更多地了解Database课程的内部工作方式,而不是他们可能应该做的。它把它们紧密地联系起来。

作为替代方法,您可以在query()类中创建一个Database方法,该方法包含其中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课程中包含每个Database方法的路径并不是一个好主意。此时,Database类的效用大大降低,您也可以直接传入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;

在你的问题标题中,你提到了注射。你的班级现在没有这样做,但提前实例化Database并将一个注入到需要它的类构造函数中是个好主意。

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连接。