0

I've been working on a databaseHandler php class, which should connect to the database and then be usable in other PHP files, atleast this was the plan. I've come across the problem that it cannot use any PDO related functions in my PHP class, i've tried checking if it was null, or not set at all (but it was) and i've also tried using a dummy function that just echos something which was to test if the class isn't undefined in others.

<?php
class databaseHandler {

    private $db;
    private static $instance;

     function __construct() {
        $this->buildDatabaseConnection();
    }

    public static function getInstance() {
        if(!self::$instance) {
            self::$instance = new databaseHandler();
        }

        return self::$instance;
    }

    private function buildDatabaseConnection() {
        require 'dbconfig.php';
        try {
    $this->db = new PDO("mysql:host=" . HOST . ";dbname=" . DATABASE . ";charset=utf8", USER, PASSWORD);
    if(isset($this->db)) {
        if(!is_null($this->db)) {
            echo "isn't null";
        }
    }
    } catch(PDOException $e) {
        $e->getMessage();
    }
    }

    public function getConnection() {
        return $this->$db;
    }

    public function getSomeShit() {
        echo "some shit";
    }


}
?>

The problem might be with the getConnection() php function, does it actually return the PDO object here? Because the main problem lays with the fact that i get this error when i use my getConnection function in other classes:

Notice: Undefined variable: database in     F:\Websites\DevProject\php\functions.php on line 69

Fatal error: Uncaught Error: Call to a member function prepare() on null in F:\Websites\DevProject\php\functions.php:69 Stack trace: #0 F:\Websites\DevProject\php\functions.php(51): register('qwe', 'sdasd', 'asdasd', 'asdas', '01-01-1970') #1 F:\Websites\DevProject\register.php(123): datelessRegister('qwe', 'sdasd', 'asdasd', 'asdas') #2 {main} thrown in F:\Websites\DevProject\php\functions.php on line 69

and line 69 would be this:

$stmnt = $database->prepare("SELECT $username, $email FROM " . USERTABLE);

Where the $database variable is the class instance:

$database = databaseHandler::getInstance();

If i try to var_dump it in my registration php file, it'll tell me this:

object(databaseHandler)#1 (1) { ["db":"databaseHandler":private]=> object(PDO)#2 (0) { } }

However, when i use it inside of my function, it will say it is 'NULL', why is it null in a function but defined globally?

All the errors relate to the object, and in there it tells me the pdo is undefined (i've tried checking if it was null, but it wasn't!)

Any help would be great, thanks in advance.

  • Do a `var_dump($database);` You'll see that it is a null object. – hjpotter92 Nov 21 '16 at 08:57
  • @hjpotter92 it is not null, the text i get from this is: `object(databaseHandler)#1 (1) { ["db":"databaseHandler":private]=> object(PDO)#2 (0) { } }` –  Nov 21 '16 at 09:01
  • What line number does your `$database = ` happen? – bradynpoulsen Nov 21 '16 at 09:04
  • @bradynpoulsen It seems that it isn't null when i define it ontop of the file as variable, but in the function it will be null, not sure why this is so. –  Nov 21 '16 at 09:06
  • Certainly read https://phpdelusions.net/pdo/common_mistakes. If `databaseHandler` doesn't do anything useful on its own, omit it, use a `PDO` instance directly. – deceze Nov 21 '16 at 09:06
  • For one, you're returning an instance of `databaseHandler`, and seem to expect that it has a method `prepare`, which it doesn't. You'd have to call `$database->getConnection()->prepare()` for that to work. In which case… why that additional wrapper? – deceze Nov 21 '16 at 09:08

3 Answers3

3

In the return statement of getConnection method you should write the class variable without $:

return $this->db;

Also, you must do the queries on the PDO connection instead of your database handler class, so $database = databaseHandler::getInstance(); should be

$database = databaseHandler::getInstance()->getConnection();

or you can simply use the __call magic method to keep your code as it is right now:

public function __call($method, $args)
{
    return call_user_func_array(array($this->db, $method), $args);
}

Also, to clarify how to use this class, you should call it inside every method you need the database to be used, not only once on the top of your file, because defining it there it will not be available inside your methods/functions unless you don't use the global statement to import the variable. However usage of the global variable is not encouraged and it is considered as a bad practice. An example on how to use the database would be:

public function doSomething()
{
    $db = databaseHandler::getInstance()->getConnection();
    $db->prepare(....);
}

public function doSomethingElse()
{
    $db = databaseHandler::getInstance()->getConnection();
    $db->prepare(....);
}

If you know there are many methods inside your class that uses the database then you can define it as a class variable and set the db instance in the constructor.

Mihai Matei
  • 24,166
  • 5
  • 32
  • 50
  • That, i did not see. However this does not solve my problem. Thanks for the input though! –  Nov 21 '16 at 09:06
  • Take a look at the updated answer – Mihai Matei Nov 21 '16 at 09:10
  • 1
    *"to keep your code as it is right now"* - OP should rather be changing their current code than start shoving in hacks to keep it as it is… – deceze Nov 21 '16 at 09:11
  • This answer is now out of scope. Speaking of scope, the commentary on his question makes it sound like a variable scope issue, not a class definition issue – bradynpoulsen Nov 21 '16 at 09:12
  • 1
    @bradynpoulsen I saw your answer but you shouldn't encourage him to use global variables.. Doing it like that is wrong and it is against the scope of creating a singleton class for getting the db connection.. – Mihai Matei Nov 21 '16 at 09:16
  • @MateiMihai It's definitely worth clarifying the point of singletons in the first place, but using the global variable isn't wrong lol. Not recommended in practice, but the point of the answer is that he's experiencing an unfortunate common problem that isn't due to his class definition – bradynpoulsen Nov 21 '16 at 09:28
0

The problem seems to be in the getConnection() function. Since $db is field you must do.

return $this->db;

However this is a very complex class structure for a simple problem. You can directly extend your class from PDO

class DatabaseHandler extends PDO {
    function __construct() {
        parent::__construct('mysql:host=host_name;dbname=db_name', 'user_name', 'password');
        parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
}

And create an object of this whenever you want to do database transaction.

$db = new DatabaseHandler();
$stmt = $db->prepare(".....");
$stmt->execute();
Samuel Robert
  • 10,106
  • 7
  • 39
  • 60
0

You seem to be having issues with scopes.

$database = databaseHandler::getInstance();

function doSomething()
{
    // $database is not defined in this scope
    $database->getConnection()->prepare(/* ... */);
}

You have to declare it as part of the global scope

function doSomething()
{
    global $database;
    $database->getConnection()->prepare(/* ... */);
}
bradynpoulsen
  • 365
  • 3
  • 11