1

I started learning PDO and im still a bit of a PHP novice. Im doing a project to increase my knowledge but im stuck at the first hurdle.

Im getting this error: Call to a member function prepare() on a non-object on line 37 of this code. This is from database.class.php

<?php
// Include database class
include 'config.php';

class Database{
private $host      = DB_HOST;
private $user      = DB_USER;
private $pass      = DB_PASS;
private $dbname    = DB_NAME;

private $dbh;
private $error;

public function __construct(){
    // Set DSN
    $dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;
    // Set options
    $options = array(
        PDO::ATTR_PERSISTENT    => true,
        PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION
    );
    // Create a new PDO instanace
    try{
        $this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
    }
    // Catch any errors
    catch(PDOException $e){
        $this->error = $e->getMessage();
    }
}

// this variable holds the temporary statement
private $stmt;

// prepare our values to avoid SQL injection
public function query($query){
    $this->stmt = $this->dbh->prepare($query);
}

// use switch to select the appropiate type for the value been passed
// $param = placeholder name e.g username, $value = myusername
public function bind($param, $value, $type = null){
    if (is_null($type)) {
        switch (true) {
            case is_int($value):
                $type = PDO::PARAM_INT;
                break;
            case is_bool($value):
                $type = PDO::PARAM_BOOL;
                break;
            case is_null($value):
                $type = PDO::PARAM_NULL;
                break;
            default:
                $type = PDO::PARAM_STR;
        }
    }
// run the binding process
$this->stmt->bindValue($param, $value, $type);
}

// execute the prepared statement
public function execute(){
    return $this->stmt->execute();
}

// returns an array of the results, first we execute and then fetch the results
public function resultset(){
    $this->execute();
    return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}

// same as resultset() except this returns a single result
public function result_single(){
    $this->execute();
    return $this->stmt->fetch(PDO::FETCH_ASSOC);
}

// count the number of rows from the previous delete, update or insert statement
public function rowCount(){
    return $this->stmt->rowCount();
}

// last insert id return the last id of the insert made, useful if you need to run a further
// query on the row you just inserted and need the id as the reference
public function lastInsertId(){
    return $this->dbh->lastInsertId();
}

// transactions allow you to rollback if a set of queries fail but it also allows ensures
// we avoid errors due to users interaction while half of the queries are still being written

// the following code begins a transaction
public function beginTransaction(){
    return $this->dbh->beginTransaction();
}

// end a transaction
public function endTransaction(){
    return $this->dbh->commit();
}

// rollback a transaction
public function cancelTransaction(){
    return $this->dbh->rollBack();
}

// this dumps the PDO information from the prepared statement for debug purposes
public function debugDumpParams(){
    return $this->stmt->debugDumpParams();
}

}

?>

Now the initial page im running this code in index.php

<?php

// Include database connection class
include 'includes/database.class.php';
include 'includes/bug.class.php';

$database = new Database;
$bugs = new Bugs;
$bugs->find_all_rows();

echo "<pre>";
print_r($rows);
echo "</pre>";

echo "Number of rows: " . $bugs->rowCount() . "<br />";


?>

And this is the page it would be running the find_all_rows function on which is the bugs.class.php file

<?php
class Bugs {

    public function find_all_rows() {
      return self::find_by_sql('SELECT * FROM tbl_priority');   
    }

    public function find_by_sql($sql="") {
      global $database;
      $database->query($sql);
      $rows = $database->resultset();

      return $rows;
    }
}
?>

Is there a debug tool that will help me trace these type of errors better or is it just a case im not familiar enough with PDO to spot an obvious mistake?

pajaja
  • 2,164
  • 4
  • 25
  • 33
user1547410
  • 863
  • 7
  • 27
  • 58
  • What is the value of `$this->error` ? Why don't you give `class Bugs` it's very own Database object so that you are sure it instantiated? (This is one of the 'laws' of OOP) – AmazingDreams Aug 04 '13 at 18:33
  • Its a server error so its not even loading the index page, ive just started learning Pdo so im sure there is probably big mistakes above, im just looking for a bump in the right direction, once i get a couple of queries working i think ill be able to figure most of it out from there – user1547410 Aug 04 '13 at 18:36
  • When you say give class bugs its own database object do you mean do Class Bugs extends Database? – user1547410 Aug 04 '13 at 18:37
  • 1
    Unfortunately, this is not a code review site to watch out all the big mistakes above. You have to write your code step by step, not all in once. Debug each part seprately. – Your Common Sense Aug 04 '13 at 18:39
  • The error you get said that `$this->dbh` is not an object, which most likely means that `$this->dbh = new PDO($dsn, $this->user, $this->pass, $options);` failed. You don't see that right away since you are handling that exception. – pajaja Aug 04 '13 at 18:40
  • Im not looking for you to review all my code, i just put up all the parts that might be relevant, i am trying to figure out what is causing the error, i do not know what the error means, i could go back to mysql instead of PDO but everytime i post with those everyone tells me to learn PDO, i took that advice on board and here i am – user1547410 Aug 04 '13 at 18:41
  • This may help: [How to squeeze error message out of PDO?](http://stackoverflow.com/q/3726505) – Pekka Aug 04 '13 at 18:42
  • I commented out the find all rows function and i dont get an error, since i call New Database in the index which runs $this->dbh = new PDO($dsn, $this->user, $this->pass, $options); then i presume this is running ok and might be someething else? – user1547410 Aug 04 '13 at 18:45
  • When you comment that function call you are not running any SQL queries, right? That's why you don't get any errors. Put the `$this->dbh = new PDO(...);` outside the try-catch block which handles `PDOException` and see if there is no error. – pajaja Aug 04 '13 at 18:49

2 Answers2

2

@papaja hit the nail right on the head. Your PDO connection failed, thus you do not have a PDO object to run the prepare method on.

Off the top of my head, I think you are missing the end quote on the $dsn string. You probably want to add the following after $this->dbname and before the semi-colon:

. "'"

That's a single quote wrapped in double quotes. I use the following syntax to create the DSN string:

"mysql:host=$this->HOST;dbname=$this->DATABASE"

Anyway, create a test file so that you know exactly what the problem is. The test file should look like this:

class TestDatabase{

    private $host      = DB_HOST;
    private $user      = DB_USER;
    private $pass      = DB_PASS;
    private $dbname    = DB_NAME;
    private $dbh;


    public function __construct(){

        $dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;

        $options = array(
            PDO::ATTR_PERSISTENT    => true,
            PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION
        );

        $this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
    }
}

Note that we are not running the instantiation of the PDO object within a try catch block. While you would never ever do that in production, it will be useful for your test because it will throw a fatal exception containing all of the details of your connection.

Now instantiate the test class and proceed by debugging the errors you receive. Again, they will be more detailed than the previous error because it will be an uncaught PDO exception.

Neil Girardi
  • 4,533
  • 1
  • 28
  • 45
0

Get same error and couldn't fix with code written above.

Here is easy fix as in your code this is the problem why PDO Sending Error :

public function __construct(){
    // Set DSN
    $dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;
    // Set options
    $options = array(
        PDO::ATTR_PERSISTENT    => true,
        PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION
    );
    // Create a new PDO instanace
    try{
        $this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
    }
    // Catch any errors
    catch(PDOException $e){
        $this->error = $e->getMessage();
    }
}

I am using PHP 5.5 and if someone have same error then he will need this

After $dns you need to add this where $this->dbname . ";";

Only this is how it will work for PHP 5.5 and Will not work with $this->dbname . "'";

public function __construct(){
    // Set DSN
    $dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname . ";";
    // Set options
    $options = array(
        PDO::ATTR_PERSISTENT    => true,
        PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION
    );
    // Create a new PDO instanace
    try{
        $this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
    }
    // Catch any errors
    catch(PDOException $e){
        $this->error = $e->getMessage();
    }
}
Mandeep Gill
  • 390
  • 5
  • 12