Jump to content

Extending PDO while keeping a Singleton happy


Xeoncross

Recommended Posts

 

After diving into PDO I found that I still wanted "helper" functions that would do things like help me to sort column types and stuff. So I built a simple script to handle the PDO connection but now I am wondering how to implement helper functions. I thought of two ways:

 

1) I could leave them as functions (mysql_column_info() and sqlite_column_info())

2) I could build a custom class that was my abstraction between the PDO and added my methods based on the type of database.

3) I could build a second DB class that has the helper functions

 

I don't really want to have 5-15+ "helper functions" for different DB's just floating around my system - and I really don't want to try to abstract over the PDO system.

However, before I build a second "helper" class that contains addition functions based on the DB type - I wanted to ask if anyone had a better way?

 

 

 

Here is a simple version of a PDO class:

<?php

class db {

    // Declare instance
    private static $instance = NULL;

    /**
    * The constructor is set to private so
    * no one can create a new instance using new
    */
    private function __construct() {
      /*** maybe set the db name here later ***/
    }
    
    /**
    * Like the constructor, we make __clone private
    * so nobody can clone the instance
    */
    private function __clone(){}

    /**
    * Return DB instance or create intitial connection
    *
    * @return object (PDO)
    * @access public
    */
    public static function instance() {
        if (!self::$instance) {
            //self::$instance = new PDO("mysql:host='localhost';dbname='animals'", 'username', 'password');
            self::$instance = new PDO("mysql:host=localhost;dbname=pdo", 'root', 'admin');
            self::$instance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        return self::$instance;
    }


}

//Get the Singleton instance of the DB connection
$db = DB::instance();

//Run a query
$statment = $db->query('SELECT * FROM animals');
$result = $statment->fetch(PDO::FETCH_ASSOC);

foreach ($result as $key => $value) {
    echo $key.' - '.$value.'<br />';
}

?>

Link to comment
Share on other sites

This is NOT a Singleton. Db isn't the same class as PDO.

 

class db is a simple object wrapper to provide a Singleton instance of the PDO object. I could do it with a function too.

I just want to avoid global $db; when using PDO in functions and methods. So what is wrong with this?

 

 

I would go with option number 2. Just a basic Decorator would do the trick.

 

What if I had several classes like: sqlite_helper, mysql_helper, firebird_helper and I wanted to extend a class that was a wrapper for the PDO object like you said. How would I add optional functionality to a db class like what is above?

 

 

 

Link to comment
Share on other sites

class db is a simple object wrapper to provide a Singleton instance of the PDO object. I could do it with a function too.

I just want to avoid global $db; when using PDO in functions and methods. So what is wrong with this?

 

Nothing wrong with it (aside from some stuff you find in Singletons as well). But it's not a Singleton. Terminology is everything.

 

What if I had several classes like: sqlite_helper, mysql_helper, firebird_helper and I wanted to extend a class that was a wrapper for the PDO object like you said. How would I add optional functionality to a db class like what is above?

 

If you can afford it, more abstraction it usually better. If you don't know how to accomplish that, or need some specific help, I'd be pleased to help out. Adding functionality to an existing class can be done in a million different ways.... If you show us something that clearly illustrates your intentions, I can help, otherwise, not.

Link to comment
Share on other sites

This is really far off the mark - but you get the idea:

 

<?php

abstract class db {
    public static function instance() {
        if (!self::$instance) {
            //self::$instance = new PDO("mysql:host='localhost';dbname='animals'", 'username', 'password');
            self::$instance = new PDO("mysql:host=localhost;dbname=pdo", 'root', 'admin');
            self::$instance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        return self::$instance;
    }
}

class mysql_helper extends db {
    function column_data {
        print 'Mysql Column Data';
    }
}

class sqlite_helper extends db {
    function column_data {
        print 'Sqlite Column Data';
    }
    function nonstandardextrafunc() {
        print 'Hello';
    }
}

class mssql_helper extends db {
    function column_data {
        print 'MSSQL Column Data';
    }
}


$db = DB::instance();

$db->query('SELECT * FROM table');
$db->column_data();
?>

 

The fictitious function "column_data()" is just an example of adding a function to the PDO to help manage SQL data.

 

Link to comment
Share on other sites

That isn't going to work. You'll have to wait for PHP 5.3 and late static binding. Also, you should implement nonstandardextrafunc in all subclasses. That's what polymorphism is about. Try to sensibly emulate the features.

 

 

Link to comment
Share on other sites

You'll have to wait for PHP 5.3 and late static binding.

 

"Late Static Binding" huh? I'll need to look into that.

 

Anyway, after I posted on this I found a topic in which someone EXTENDED the PDO class. DUH!

I thought that since it was part of PHP it couldn't be extended! So the following code works fine.

 

However, is there any problem with doing it this way?

 

<?php

//The type of database
$database_type = 'mysql';

//Two classes that add extra stuff to PDO
class mysql extends PDO {
    function column_data() {
        print 'Mysql Column Data';
    }
}
class sqlite extends PDO {
    function column_data() {
        print 'Sqlite Column Data';
    }
}


class db {

    // Declare instance
    private static $instance = NULL;

    /**
    * Return DB instance or create intitial connection
    */
    public static function instance() {
        //Get the type of database we are using
        global $database_type;
        
        if (!self::$instance) {
            self::$instance = new $database_type("mysql:host=localhost;dbname=pdo", 'root', 'admin');
        }
        return self::$instance;
    }


}



//Get the Singleton instance of the DB connection
$db = db::instance();


//Run a query
$statment = $db->query('SELECT * FROM animals');
$result = $statment->fetch(PDO::FETCH_ASSOC);

foreach ($result as $key => $value) {
    echo $key.' - '.$value.'<br />';
}

//Also run my custom function
$db->column_data();
?>

Output: 
animal_id - 1
animal_type - kookaburra
animal_name - bruce
Mysql Column Data

Link to comment
Share on other sites

 

Ok, I am having some trouble with PDO::prepare() to create queries which can later have values added.

 

<?php
/* Execute a prepared statement by passing an array of values */
$sql = 'SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour';
$sth = $dbh->prepare($sql);

//Run the Code replacing values with new ones
$sth->execute(array(':calories' => 150, ':colour' => 'red'));

//Get result
$red = $sth->fetchAll();

?>

 

 

Now the problem I am having is that I need to PDO::quote() objects before I put them in the query - and I don't know if they will be ':value', '?', or 'A real value that could be XSS'. (this is a simple class for helping to me make SQL queries)

 

 

<?php
/**
     * Creates the in() part of a query.
     */
    public function in_list($data=array()) {
        $output = ' in(';
        
        foreach((array) $data as $value) {
            /*
            if(substr($value, 0, 1) == ':') {
                $output .= $value. ',';
            } else {
                $output .= $this->quote($value). ',';
            }
            */
            $output .= $value. ',';
        }
        return rtrim($output, ','). ')';
        
    }
?>

 

I would just $this->quote() everything and not worry about it - but if the values I used are going to be replaced when I run PDOStatement::execute() - it also runs the PDO::quote() again! So if I quote my values they might become:

'\':value\''

'\'?\''

'\'A real value that could be XSS\''

 

 

and I if I don't and they might be:

:value

?

A real value that could be XSS

 

So I need to figure out how to know if a value is a replacement value or if it is a final value that won't be replaced. The PDO manual states that ? and :value are the way to do it.

 

 

 

 

Link to comment
Share on other sites

  • 3 months later...
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.