Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class extending PDO - parent::__construct does not work, but creating a new PDO does

I am trying to write a PDO wrapper but I'm having some problems with the constructor. Ideally, I would like to call the parent's constructor but, for some reason, that is not working. I tried (to test) to check if creating a new PDO and that does work, which I find most confusing.

Here is my code:

class db extends PDO {

    private $dbconn;

    public function __construct() {
        $dsn = 'mysql:dbname=' . MYSQL_DB . ';host=' . MYSQL_HOST;
        $user = MYSQL_USER;
        $pw = MYSQL_PW;
        try {
            $this->dbconn = parent::__construct($dsn, $user, $pw);
            $this->dbconn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $this->dbconn;
        }
        catch(PDOException $e) {
            echo 'Connection failed: ' . $e->getMessage();;
        }


    }
}

It works if I replace the parent:: line with $this->dbconn = new PDO($dsn, $user, $pw);

I believe that the "correct/elegant" way to do it is to use the parent:: syntax so I would like to know why that is not working/how I can fix it. Anyone can help?

Thank you!

like image 316
David Avatar asked Nov 22 '11 20:11

David


3 Answers

__construct() doesn't have a return value and when you extend a class your custom one is of the type of the extended one. This means (in your case) an object of db is also an object of PDO

At all

$dsn = 'mysql:dbname=' . MYSQL_DB . ';host=' . MYSQL_HOST;
$user = MYSQL_USER;
$pw = MYSQL_PW;
parent::__construct($dsn, $user, $pw);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Thats the whole constructor you need

like image 27
KingCrunch Avatar answered Oct 17 '22 05:10

KingCrunch


That's not how you use constructors, as they don't return anything. Try the following instead:

public function __construct() {
    $dsn = 'mysql:dbname=' . MYSQL_DB . ';host=' . MYSQL_HOST;
    $user = MYSQL_USER;
    $pw = MYSQL_PW;
    try {
        parent::__construct($dsn, $user, $pw);
        $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    catch(PDOException $e) {
        echo 'Connection failed: ' . $e->getMessage();;
    }
}

NOTE: You may still run into issues, as your constructor doesn't accept the same arguments as the PDO constructor. One of the tenets of OOP is that of equivalence, as embodied in the Liskov Substitution Principle, which means that the protocol (public API) of a subclass should be a strict superset of its superclass. The reason this is important is that if the subclass has an API that differs from the one presented by the class it inherits from, then it can't be used to substitute for the superclass in all cases.

For example, how would you use your subclass to connect to a PostgreSQL database or use a SQLite file instead of using mysql? The PDO superclass can work with all three, along with other database back ends, by virtue of the fact you can pass a DSN in as an argument, but you can't do that with your subclass.

However, all this is getting into aspects of computer science and is drifting off topic somewhat ;)

like image 192
GordonM Avatar answered Oct 17 '22 06:10

GordonM


This example allows me to simplify connection string in my software.

$db = new epdo('MyDataBase');

It also allows for different server, username and password only and if required. Hope this helps:

class epdo extends PDO {
    public function __construct($dbname, $server='127.0.0.1', $username='usernamehere', $password='passwordhere') {
        parent::__construct("mysql:host=$server;dbname=$dbname", $username, $password);
        parent::setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

        // error reporting (only show errors on localhost)
        if( $_SERVER['SERVER_ADDR'] == '127.0.0.1') {
            parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
        } else {
            parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
        }
     }
}
like image 40
Frankos Avatar answered Oct 17 '22 05:10

Frankos