1

I'm fairly new to PHP; however I think I have a good grasp on it, but I'm having an issue understanding why I'm not able to access a second version of a connect to DB class I have.

I connect globally to the first one in a config script.

$db = new db(array('login info'));

I access it in my controller using the following.

public $db;
public function __construct(){
    $this->db = $GLOBALS['db'];
}

Then inside my controller I have a function where I create a new instance of this to connect to a different DB.

$ordersDB = new db(array('login info'));

Now I would like to access each database separately using something like

$this->db->select("SELECT * FROM ada Yada 

and

$ordersDB->select("SELECT * FROM Yada Yada

However both are still accessing the first db. I know this because I am getting a table does not exist error when executing the second one and it tells me what db its querying. However a var_export of them shows they are infact different! Am I completely misunderstanding how classes work or can I only have one DB open at a time? Thanks for any help.

Edit: Is this what you are looking for?

$db = new db(array(connect info));
$controller = new controller();
$controller->connectToSecondDB();

class db {

    public $dbHost;
    public $dbUser;
    public $dbName;
    public $dbPassword;

    public function __construct() {
       $arguments = func_get_args();

       if(!empty($arguments)){
          foreach($arguments[0] as $key => $property){
            if(property_exists($this, $key)){
                $this->{$key} = $property;
            }
           }
       }
    }

  public function connect() {            
        if(!isset(self::$connection)) {       
            self::$connection = new mysqli($this->dbHost, $this->dbUser, $this->dbPassword, $this->dbName);
        }
}

class controller {
   public $db;
   public function __construct(){
      $this->db = $GLOBALS['db'];
   }

   public function connectToSecondDB(){
      $ordersDB = new db(array(connect info));
      $ordersDB->select("SELECT * FROM `customer` WHERE email = 'email@address.com' LIMIT 1")
      $this->db->query("SQL");
   }
}

EDIT Select Query Function

private function _sel($table, $where="", $order_by="", $limit="", $group_by="",$database = NULL){
        if($database === NULL) {  $database = $this->db; }
        if($limit == 1){ $single = true; }else{ $single = false; }

        //if( is_array($where) ){ $this->_buildWhere(); }
        $where = (strlen($where) > 0) ? "WHERE $where " : $where;       
        $group_by = (strlen($group_by) > 0) ? "GROUP BY $group_by " : $group_by;        
        $order_by = (strlen($order_by) > 0) ? "ORDER BY $order_by " : $order_by;        
        $limit = (strlen($limit) > 0) ? "LIMIT $limit " : $limit ;

        $sql = "SELECT * 
                FROM `$table` 
                $where 
                $group_by 
                $order_by 
                $limit";
        // Debug

//if(INCLUDE_CHECK){ echo "<HR>".$sql."<HR>";   }
        $results = $database->select($sql); 
        if($single && count($results) > 0 ){
            return($results[0]);
        }else{
            return($results);
        }
    }
user3167249
  • 1,082
  • 2
  • 14
  • 28
  • 1
    Can you create and post a [short, Self Contained, Correct (Compilable), Example](http://sscce.org/) that shows the problem in its entirety? – VolkerK Oct 10 '15 at 22:51
  • @VolkerK is this what you are looking for? – user3167249 Oct 10 '15 at 23:01
  • imho a lot of other code is missing in order to find the mistake (e.g. the constructor of db) and please use OO naming convention: class names are concatenated words starting with upper case (e.g. MyClass) – leonixyz Oct 10 '15 at 23:11
  • Looks like your `class db` "hides" a [singleton](https://en.wikipedia.org/wiki/Singleton_pattern) inside its constructor. – VolkerK Oct 10 '15 at 23:18
  • @leonixyz I have added the constructor. – user3167249 Oct 10 '15 at 23:20
  • `self::` references the class, not the instance. see [Static Keyword](http://docs.php.net/manual/en/language.oop5.static.php) and [Late Static Bindings](http://docs.php.net/manual/en/language.oop5.late-static-bindings.php) – VolkerK Oct 10 '15 at 23:21
  • @VolkerK What do you mean by that? I have posted the construct function. – user3167249 Oct 10 '15 at 23:22
  • @VolkerK so should I use $this-> instead? This DB class was actually one I found online so it's not my code. – user3167249 Oct 10 '15 at 23:23
  • Don't just copy&paste code. copy&paste&understand is ok. – VolkerK Oct 10 '15 at 23:24
  • @VolkerK :) I thought I understood it fairly well. I read though it to make sure I knew what was going on, but I guess I assumed that self meant that it was just interchangeable with $this-> – user3167249 Oct 10 '15 at 23:27
  • You've got the answer. Use `$this->` instead of `self::` It will solve your problem. See [here](http://stackoverflow.com/questions/151969/when-to-use-self-vs-this) for more info. – mseifert Oct 10 '15 at 23:29
  • @mseifert lol. Thank you I was actually just reading that same post. – user3167249 Oct 10 '15 at 23:31
  • "I assumed that self meant that it was just interchangeable with $this->" It's not ;-) But I'm hesitant to confirm that using $this-> instead of self:: will solve your immanent problem ...because I'm biased as can be against those one-off, ad-hoc ...grrrr.... database-classes. I have to assume it's one of those "credential-holder + encapsulate the exact same functionality as the underlying api only way,way worse" classes. – VolkerK Oct 10 '15 at 23:32
  • @VolkerK It does work, but I get the warning "Strict Standards: Accessing static property db::$connection as non static" – user3167249 Oct 10 '15 at 23:51
  • You don't show where you declared the class variable $connection, – mseifert Oct 11 '15 at 00:00
  • @mseifert it was defined as protected static $connection; I have since removed the static and now the warnings are gone. However. I'm concerned now. With these changes am I making a new connection to the DB for each query I run? – user3167249 Oct 11 '15 at 00:04
  • my function that runs the query looks like this private function _sel($table, $where="", $order_by="", $limit="", $group_by="",$database = NULL){ if($database === NULL) { $database = $this->db; } So I can use the default unless I need to for a specific situation. – user3167249 Oct 11 '15 at 00:06

1 Answers1

1

A solution is to reuse your $controller object. Add a query method. Then you can run the query separate from the connection method so the controller object can be reused

You need error checking each step along the way.

Note that I removed $this->db->query("SQL"); as I am not sure what exactly it did. The concept in the answer should get you started redesigning your class.

UPDATE Based on comment, I changed the $db from a super global and passed it to the controller object.

$db = new db(array(connect info));
// try passing the $db object so it does not need to be a super global
$controller = new controller($db);
// You can keep your $controller object as a global - I use a session variable for this to reuse it between pages.
$controller->connectToSecondDB();
// run the query separate from the connection so the controller object can be reused
$result = $controller->ordersQuery("SELECT * FROM `customer` WHERE email = 'email@address.com' LIMIT 1")


class db {

    public $dbHost;
    public $dbUser;
    public $dbName;
    public $dbPassword;
    public $connection;

    public function __construct() {
       $arguments = func_get_args();

       if(!empty($arguments)){
          foreach($arguments[0] as $key => $property){
            if(property_exists($this, $key)){
                $this->{$key} = $property;
            }
           }
       }
    }

  public function connect() {            
        if(!isset($this->$connection)) {       
            $this->connection = new mysqli($this->dbHost, $this->dbUser, $this->dbPassword, $this->dbName);
        }
}

class controller() {
   public $db;
   public $ordersDB;    // ADD THIS

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

   public function connectToSecondDB(connect info){
      $ordersDB = new db(array(connect info));
   }

   public function ordersQuery($sql){
      $this->ordersDB->query($sql)
      // Fetch and return you result set here
   }

}
mseifert
  • 5,390
  • 9
  • 38
  • 100
  • I noticed you still have the "self::$connection = new mysqli($..." is that by design? That is what I changed to get it to work properly. Also all of my DB calls are inside the controller. Meaning I don't ever do a $controller->query because once the controller is done processing there is no need to query the DB again. Does this have basically the same effect as you mentioned? – user3167249 Oct 11 '15 at 00:23
  • Good catch. I was focused on the other changes. I've updated it to reflect. More changes are still needed. For example, what is `$this->db->query("SQL"); ` supposed to do? – mseifert Oct 11 '15 at 00:26
  • That was just to show that I was running a query there. I actually have a function inside the controller class that runs all the queries. I have edited the main post to show this function in its entirety. – user3167249 Oct 11 '15 at 00:33
  • Good. You should be able to replace my select with yours and pass the db object to it. Good luck. – mseifert Oct 11 '15 at 00:36
  • 1
    You should realy not rely on superglobals anymore. Pass your DB instance to the constructor. This is a far better aproach – DarkBee Oct 11 '15 at 00:43
  • @DarkBee I totally agree. I should have presented the code to reflect this. I will make this change – mseifert Oct 11 '15 at 00:58
  • ..and chances are that `class db` should be dropped all together. It doesn't seem to provide any abstraction and if the the remaining methods are as convoluted as the constructor ...just drop it and use e.g. [PDO](http://docs.php.net/pdo) instead (not a database abstraction either but a reasonably unified access layer). – VolkerK Oct 11 '15 at 06:36
  • @VolkerK - Yes, the db class should be absorbed into the controller class and many more changes besides. But as the user says, they are "fairly new to PHP" and they will figure this out down the road. It would be great to have a SO code repository to point users to and say, Here are a few standard ways to create your abstract database classes. – mseifert Oct 11 '15 at 06:55
  • I admit that I'm ticked off by `class database { return mysql_query("...$param") }`, `class email { strcpy "\r\n"}` and `class ringbuffer` but on the other hand too lazy to try writing a comprehensive post about those "beginners, _on your level_ those things are solved problems. Don't reinvent it, you will do it wrong. Just use and learn from the existing _solutions_"-thingys. ;-) – VolkerK Oct 11 '15 at 07:09