Search code examples
phpdesign-patternspdosingletondbal

PHP - How do I replace this Singleton? - Custom DBAL


I am rather new to the concepts of design patterns and I'm thinking of using Dependency Injection and Polymorphism (as each are applicable) -- but I have many Singletons and while most of them can easily be changed, my DBAL cannot.

The reason why is the DBAL creates a connection to the Database -- sets up it's own PDO object. If I passed new DBALs to every class that needs it (quite a few) I would get multiple, unnecessary connections to the database.

The class is something like this

class DB {
    /**
     * Hold the PDO object
     * @var PDO
     */
    private $_db;

    /**
     * Hold the last error messages
     * @var string
     */
    private $_error_message = NULL;

    /**
     * Hold the last error code
     * @var int
     */
    private $_error_code = NULL;

    /**
     * Connects to the database server and selects a database
     *
     * @param string $user MySQL database user
     * @param string $password MySQL database password
     * @param string $name MySQL database name
     * @param string $host MySQL database host
     * @return bool
     */
    public function connect( $user, $password, $name, $host ) {
        // Connect
        try {
            $this->_db = new PDO( "mysql:host=$host;dbname=$name", $user, $password );
        } catch ( PDOException $e ) {
            $this->_error_message = $e->getMessage();
            $this->_error_code = $e->getCode();
            return false;
        }

        return true;
    }

    // ...
}
?>

There will be many classes that inherit this class -- what is the best way to handle this? (I am new to design patterns)


Solution

  • An alternative method is to use a registry:

    $db = new DB($host, $user, $pass);
    Config::set('db', $db);
    
    // Inside other classes
    Config::get($this, 'db'); 
    // Passes $this so the config can override the DB for different classes
    

    Problem here is you end up with a Config singleton.

    To truly do DI, you basicly need to pass object around to every other object.

    $db = new DB($host, $user, $pass);
    $user = new User($db);
    // Or with a DI container
    $c = new Pimple();
    $c['db'] = function() {
        return new DB($host, $user, $pass);
    };
    

    But ask yourself why you don't want to use a singleton.

    If it looks like a singleton, smells like a singleton, and you use it like a singleton, then a singleton pattern is probably the best fit for the job.

    http://pimple.sensiolabs.org/