在我的应用程序中,我只使用了一个数据库,并创建了类来提供一些常用方法。 现在我需要实现额外的数据库。
因此,我不想创建单独的Db类来做同样的事情,而是想用db相关参数调用该Db类。
问题是,当我尝试使用我向app提供方法的类扩展Db类时,数据库连接尚未建立 - 它为空。
Main和User都在使用不同的数据库。
Class Main扩展Db; 类用户扩展Db;
为什么这样的事情不起作用?
class Db {
protected $link;
private $host;
private $user;
private $pass;
private $dbName;
public function __construct($host, $user, $pass, $db) {
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->dbName = $db;
$this->connect();
}
public function connect() {
try
{
$this->link = new PDO("mysql:host=" . $this->host .
";dbname=" . $this->dbName . ";charset=utf8mb4", $this->user, $this->pass );
$this->link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $exc)
{
$this->setMessage($exc->getMessage());
}
}
}
$db = new Db(HOST, USER,PASS,DB)
class Main extends DB {
public function __construct() {
}
/** App methods bellow*/
}
$db2 = new Db(HOST2,USER2,PASS2,DB2);
class User extends DB {
public function __construct() {
}
/** App methods bellow*/
}
实现两个不同的数据库连接最简单的解决方案是什么?
谢谢!
按照建议更新我的代码后,我遇到了访问DB的连接属性的问题,因此我无法在Main和User类中进行查询。
真正令我困惑的是,为什么这个属性对Main类不可见?
主类方法在很大程度上取决于数据库链接,我不知道如何解决这个问题。
更新的代码:
class Main {
protected $db;
public function __construct($db) {
$this->db = $db;
}
public function showFreeSlotsPerPlan() {
try
{
$SQL = "some query";
$stmt = $this->db->prepare($SQL);
/** Prepared statements bellow **/
}
}
class Db {
protected $link;
private $host;
private $user;
private $pass;
private $dbName;
public function __construct($host, $user, $pass, $db) {
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->dbName = $db;
$this->connect();
}
}
按照建议调用它:
$db = new Db(HOST, USER, PASS, DB);
$main = new Main($db);
如果我尝试调用方法f.e. showFreeSlotsPerPlan()
Fatal error: Call to undefined method Db::prepare() in /var/www/html/Master/class/Main.class.php
然后当我调试Main的实例时,我得到以下内容:
Main Object
(
[db:protected] => Db Object
(
[link:protected] => PDO Object
(
)
[host:Db:private] => localhost
[user:Db:private] => root
[pass:Db:private] => password
[dbName:Db:private] => dbname
)
)
EDIT2:
解决方法是将prepare
方法添加到DB.php
,我能够成功执行查询。
我还不确定这是最好的方法。我承认我的设计并不好:(
public function prepare($sqlQuery) {
return $this->link->prepare($sqlQuery);
}
答案 0 :(得分:1)
@u_mulder描述了您正确面临的技术问题。不会从子构造函数自动调用父Db
构造函数。您可以通过显式调用父构造函数来尝试解决此问题:
class Main extends DB
{
public function __construct()
{
parent::__construct();
}
// ...
}
问题是你的父(DB
)需要参数给它的构造函数,所以你还必须将它们传递给你的孩子:
class Main extends DB
{
public function __construct($host, $user, $pass, $db)
{
parent::__construct($host, $user, $pass, $db);
}
// ...
}
但这没有任何意义。你最大的问题是设计。相反,你应该favor composition of objects over inheritance,特别是在这种情况下。尝试重构你的课程:
class Main
{
protected $db;
public function __construct($db)
{
$this->db = $db;
}
// ...
}
$mainDb = new Db(HOST, USER,PASS,DB)
$main = new Main($mainDb);
为您的User
课程做同样的事情。执行此操作后,protected $link
课程中将不再显示您的Main
媒体资源。这是好的,因为,实际上,您的Main
和User
类不应具有该属性的可见性,因为拥有Db
类的重点是什么,无论如何?您可以通过向Db
类添加一些公开方法(例如public function query($sql, $parameters)
)来解决此问题,然后从Main
和User
类调用这些方法。
一旦你开始工作,我建议你调查Active Record Pattern,或者考虑完全废弃你的方法,转而采用已经可用的许多open source ORMs中的一个。