MilosM MilosM - 1 month ago 10
MySQL Question

Inheriting from Db class - Two databases connection | PHP

In my app I used one database only, and I created class to provide some common methods.
Now I need to implement additional database.

So instead of creating separate Db class to do same things, I want to call that Db class with db related parameters.

Problem is, when I try to extend Db class with a class where I provide methods to app, database connection isn't established - it is null.

Both Main and User are using different databases.

Class Main extends Db;
Class User extends Db;

Why something like this doesn't work?

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*/
}


What would be easiest solution to implement two different database connections?

Thanks!

Answer

@u_mulder described the technical issue you are facing correctly. The parent Db constructor is not automatically called from a child constructor. You could try to get around this by calling the parent constructor explicitly:

class Main extends DB 
{

    public function __construct() 
    {
        parent::__construct();
    }
    // ...
}

The problem is that your parent (DB) requires parameters to it's constructor, so you would have to also pass those in to your child:

class Main extends DB 
{

    public function __construct($host, $user, $pass, $db) 
    {
        parent::__construct($host, $user, $pass, $db);
    }
    // ...
}

But this makes no sense. Your biggest problem is the design. Instead, you should favor composition of objects over inheritance, especially in this case. Try restructuring your class like this:

class Main 
{
    protected $db;

    public function __construct($db) 
    {
        $this->db = $db;
    }
    // ...
}

$mainDb = new Db(HOST, USER,PASS,DB)
$main = new Main($mainDb);

And do the same for your User class. When you do this, your protected $link property will no longer be visible inside of your Main class. This is Okay, because, really, your Main and User classes should not have visibility of that property because what is the point of having a Db class, anyway? You can get around this by adding some public methods to your Db class (e.g. public function query($sql, $parameters)) that are then called from your Main and User classes.

Once you get that working, I would suggest that you look into the Active Record Pattern, or look into scrapping your approach altogether in favor of incorporating one of the many open source ORMs that are already available.

Comments