【问题标题】:accessing database class from another class从另一个类访问数据库类
【发布时间】:2016-05-24 20:05:52
【问题描述】:

我创建了自己的数据库类来简化 MySQLi 准备好的语句,我正尝试在另一个类中访问它。

我已将数据库类扩展到我的配置文件类并尝试在我的构造中运行选择查询并返回此错误:

致命错误:在第 80 行 /home/matt500b/dev2.csgoberry.com/includes/database.class.php 中的 null 上调用成员函数 prepare()

配置文件类构造:

public function __construct($username) {
    $params = parent::SELECT("SELECT users_info.*, users.username, users.lastOnline FROM users_info INNER JOIN users ON users.id = users_info.user_id WHERE users.username = ?", array('s', $username));
    $this->fname = (isset($params[0]['fname']) ? $params[0]['fname'] : null);
    /*More settings done here*/
}

但是,如果我先运行查询,然后将数据发送到构造,如下所示:

$profileData = $db->SELECT('SELECT users_info.*, users.username, users.lastOnline FROM users_info INNER JOIN users ON users.id = users_info.user_id WHERE users.username = ?', array('s', $pid));
$pclass = new user_profile($profileData);

结构为:

public function __construct($params){
        $this->fname = (isset($params[0]['fname']) ? $params[0]['fname'] : null);
}

一切都很好。当然,数据库实例是使用$db = new database(HOST, USER, PASSWORD, DATABASE, DEBUG); 调用的,我的数据库结构是:

public function __construct($db_host, $db_user, $db_pass, $db_name, $debug){
    $this->link = mysqli_connect($db_host, $db_user, $db_pass);
    mysqli_select_db($this->link, $db_name);
    $this->debug = $debug;
}

错误与这一行有关:if ($stmt = $this->link->prepare($sql)) { 并表明 $sql 为空,但是这两个查询除了来源之外完全相同(parent::SELECT$db->SELECT)。

有什么建议可以完成这项工作吗?

非常感谢

【问题讨论】:

  • $this->link 为 null 而不是 $sql。我没有在问题的代码示例中看到这行代码。你的问题很难理解,因为不清楚整个调用堆栈是什么样的。
  • $this->链接在数据库结构中定义。

标签: php mysql class mysqli


【解决方案1】:

当你扩展一个类,并且父类和子类都有构造函数时,你必须从子类调用父构造函数。如果父构造函数有参数,那么您必须 a) 在子构造函数中获取这些参数(最佳做法),或 b) 使用硬编码值(通常是不好的做法)。

我假设a)您的父类在其构造函数中建立数据库连接,或者b)您将数据库连接传递给父类。如果是后者(b),那么您必须将该数据库连接作为子类的参数并手动调用父构造函数,或者,从子类中的父构造函数重新实现任务。如果是前者(a),则上述情况属实,但您的做法不正确。类构造函数不应该工作,它不应该知道除了它的祖先和类型提示的构造函数参数之外的其他类。构造函数主体中的new 关键字通常是“代码异味”的标志——您创建了一个隐藏的依赖项。

对于一个使用数据库的类,而不是这个:

public function __construct ($username, $password) {
    // establish database connection using username and password
}

....

$myObject = new SomeClass('ausername', 'apassword');

... 这样做:

$dbConnection = establishDbConnection($username, $password); // establish connection outside of the class
$myObject = new SomeClass($dbConnection); // pass in the connection into the object

^ 叫做“依赖注入”,值得学习!

下面是调用父构造函数的例子:

class A {
    private $a1 = null;
    public function __construct($arg1) {
        // do something with the args
        $this->a1 = $arg1;
    }
}

class B extends A {
    private $a2 = null;
    public function __construct($arg1, $arg2) {
        parent::__construct($arg1);
        $this->a2 = $arg2;
    }
}

文档

【讨论】:

  • 所以当我创建一个新的 b 实例时,我需要做类似$myVar = new b ($classAParams, $classBParams); 的事情并使用 classAParams 来在类 A 的构造函数中使用吗?
  • @Matt 没错,是的,但如果 A 类在其构造函数中建立数据库连接,请查看我的注释(编辑帖子)......不是好习惯。
  • 在我的 db 类中,我使用 $db = new database(HOST, USER, PASSWORD, DATABASE, DEBUG); 创建了一个新实例(您可以在我的问题中看到 db 构造)。您是说最好将$db 的值传递给classB,而不是将A 类的参数传递给B 类?如果是这样,我将如何将$db 发送给 B 以便我可以使用数据库类而不需要使用 classA 构造?
  • 一个班级应该做一件事。因此,您有一个数据库类,它只是一个数据库类,它获取行等。不要扩展该数据库类,创建它的实例并将其传递给将使用它的对象。假设 A 类是“动物”,B 类是“狗”,它扩展了“动物”。这些类都不应该知道如何创建数据库对象,它们只是在构造函数中获取并使用它。
  • @Matt 这是一个可以帮助澄清的简单示例:pastebin.com/rwrKwYj2 如需更多阅读,请查阅 SOLID。如果您没有立即理解所有内容,请不要沮丧:)
猜你喜欢
  • 1970-01-01
  • 2019-01-05
  • 1970-01-01
  • 1970-01-01
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 2011-04-03
  • 2014-01-18
相关资源
最近更新 更多