1

I am facing a problem here with PDO::execute(). The thing is that i have 3 databases and i want to build a Singleton class and a universal query method. So my DB class structure is this:

class DB{
        private static $_instance = null;
        private $_pdo1, $_pdo2, $_pdo3,
                $_query,
                $_results,
                $_error = false,
                $_count = 0;

        private function __construct(){
            try{
                $dns1 = 'mysql:host='.Config::get('mysql1/host').';dbname='.Config::get('mysql1/dbname').'';
                $dns2 = 'mysql:host='.Config::get('mysql2/host').';dbname='.Config::get('mysql2/dbname').'';
                $dns3 = 'mysql:host='.Config::get('mysql3/host').';dbname='.Config::get('mysql3/dbname').'';
                $username1 = Config::get('mysql1/username');
                $username2 = Config::get('mysql2/username');
                $username3 = Config::get('mysql3/username');
                $password1 = Config::get('mysql1/password');
                $password2 = Config::get('mysql2/password');
                $password3 = Config::get('mysql3/password');
                $this->_pdo1 = new PDO($dns1, $username1, $password1);
                $this->_pdo2 = new PDO($dns2, $username2, $password2);
                $this->_pdo3 = new PDO($dns3, $username3, $password3);
            }catch(PDOException $e){
                die($e->getMessage());
            }
        }


        public static function getInstance(){
            if(!isset(self::$_instance)){
                self::$_instance = new DB();
            }
            return self::$_instance;
        }


        public function query($sql, $params = array()){
            $this->_error = false;
            if($this->_query = $this->_pdo1->prepare($sql) || $this->_query = $this->_pdo2->prepare($sql) || $this->_query = $this->_pdo3->prepare($sql)){
                if(count($params)){
                    $x = 1;
                    foreach($params as $param){
                        $this->_query->bindValue($x, $param);
                        $x++;
                    }
                }
                if($this->_query->execute()){
                    echo "Success";
                }
            }
        }
    }

in Line 49 i get this error:

Fatal error: Call to a member function execute() on boolean in /htdocs/DatabaseStructure/classes/DB.php on line 49

line 49: if($this->_query->execute())

Also tried but without success:

if($this->_query->execute() == TRUE)
if(!$this->_query->execute() == FALSE)

Any ideas why this is giving me an error?

BRG
  • 380
  • 6
  • 24
  • `->prepare()` returns `false` if it could not prepare the statement. You should check for errors. – Sverri M. Olsen Apr 29 '16 at 09:50
  • The Prepare has FAILED and therefore returned FALSE into the statement variable – RiggsFolly Apr 29 '16 at 09:51
  • this is why i have the getInstance....thats the concept of Singleton – BRG Apr 29 '16 at 09:53
  • Ooo you learn something every day – RiggsFolly Apr 29 '16 at 09:54
  • yes but the problemm is not in the constructor. I checked if it connects and also in the prepare i checked and it gives me true – BRG Apr 29 '16 at 09:56
  • The error message says differently. See `boolean` a prepare either returns a `PDO::Statement object` or `false` You must be getting FALSE – RiggsFolly Apr 29 '16 at 09:57
  • DB::getInstance()->query("SELECT * FROM users"); this is my query method. How am i getting FALSE? – BRG Apr 29 '16 at 10:01
  • See the Duped accepted answer, your `__construct()` is not getting called automatically of course, because its `private` – RiggsFolly Apr 29 '16 at 10:12
  • this is what i am doing exactly. Also the problemm is in the if (query1->prepare || query2->prepare || query3->prepare). But i dont understand. Can it not be able to query different databases with the same query method ? – BRG Apr 29 '16 at 10:14
  • @BRG I think I figured out the problem. Look in the `query()` method, the problem is because of the logical `OR` statement here `if($this->_query = $this->_pdo1->prepare($sql) || $this->_query ...`. With this conditional statement `$this->_query` will be evaluated to either `true` or `false`. So to make it work change the conditional statement like this: `if(($this->_query = $this->_pdo1->prepare($sql)) || ($this->_query = $this->_pdo2->prepare($sql)) || ($this->_query = $this->_pdo3->prepare($sql))){ ...` – Rajdeep Paul Apr 29 '16 at 10:36
  • @RiggsFolly In my opinion I think this question has been closed with wrong duplicate. I've stated the root cause of this issue in my [above comment](http://stackoverflow.com/questions/36934928/fatal-error-execute-on-boolean#comment61431326_36934928). – Rajdeep Paul Apr 29 '16 at 10:38
  • @RajdeepPaul You could be right. I have to admit I thought there was something HINKY about that line of code, obviously didn't give it enought thought. I still think that the __construct may not be getting called though. I have reopened the question. – RiggsFolly Apr 29 '16 at 10:47
  • @RiggsFolly I've pointed out the relevant things in my answer. Thanks for reopening the question. *Cheers!* ;-) – Rajdeep Paul Apr 29 '16 at 12:45

1 Answers1

3

Look at this line in your query() method,

if($this->_query = $this->_pdo1->prepare($sql) || $this->_query = $this->_pdo2->prepare($sql) || $this->_query = $this->_pdo3->prepare($sql)){ ...

The problem is because of the wrong grouping of logical OR conditions. With this conditional statement $this->_query will always be evaluated to either true or false.

Here are two sample examples to illustrate this point:

To make it work, change the conditional statement like this:

if(($this->_query = $this->_pdo1->prepare($sql)) || ($this->_query = $this->_pdo2->prepare($sql)) || ($this->_query = $this->_pdo3->prepare($sql))){ ...

So your query() method should be like this:

public function query($sql, $params = array()){
    $this->_error = false;
    if(($this->_query = $this->_pdo1->prepare($sql)) || ($this->_query = $this->_pdo2->prepare($sql)) || ($this->_query = $this->_pdo3->prepare($sql))){
        if(count($params)){
            $x = 1;
            foreach($params as $param){
                $this->_query->bindValue($x, $param);
                $x++;
            }
        }
        if($this->_query->execute()){
            echo "Success";
        }
    }
}

And to test the code, run a simple query like this:

DB::getInstance()->query("SELECT * FROM users");
Rajdeep Paul
  • 16,887
  • 3
  • 18
  • 37