0

I currently have multiple classes that all depend on one class, the Database class. Each class requires an instance of the Database class to function, and with that, I am a little concerned.

Before I convert all my procedural code to object-oriented code I need to figure this out. I Currently have one database connection for the entire program. However, from what I understand when I convert my code to OOP I will have multiple classes all with open database connections within the same program. (all of these classes will be included in the main program file).

How do I implement this correctly? I'm assuming having 5 open database connections within the same program is certainly not the correct way.

Steffan Long
  • 337
  • 2
  • 11
  • you might find this topic relevant: http://stackoverflow.com/questions/11369360/how-to-properly-setting-up-pdo-connection – tereško Mar 30 '13 at 12:51

3 Answers3

1

If you have classes that depend on database abstraction then Dependency Injection is the way to go.

class PDOProvider extends PDO
{
    public function __construct()
    {
        try { 

          parent::__construct(...); 
          $this->setAttribute(....);

        } catch(PDOException $e){
            die($e->getMessage());
        }
    }
    // ...
}

class Users
{
    private $provider; 

    public function __construct(PDOProvider $provider) // <- Injecting class dependency
    {
       $this->provider = $provider;
    }

    public function insert(array $stuff)
    {
       try {

        $this->provider->prepare("INSERT ...");
        $this->provider->execute(array(..));

       } catch(PDOException $e){
          //...
       }
    }
}
Yang
  • 8,267
  • 7
  • 30
  • 53
  • In this case, using dependency-injection as you've demonstrated is great. However it is not so great to let the model know about the database... It should be considered a service layer and be decoupled from the model. What if you want to change your model-service layer to something else? Then you're in trouble! – Centril Mar 30 '13 at 12:35
  • Here's some thoughts for consideration: http://stackoverflow.com/questions/5863870/how-should-a-model-be-structured-in-mvc/5864000#5864000 – Centril Mar 30 '13 at 12:54
0

You could share a database connection between several different objects by supplying it as an argument to the constructor, or you could create a singleton to serve the other classes with the database connection.

Passing the database connection to constructor

class Foo {

    private $database = null;

    public function __construct(&$database) {
        $this->database = $database;
    }
}
$connection = mysql_connect(..);
$bar = new Foo($connection);

Singleton

class DatabaseConnection {

    private static $instance = null;

    private function __construct() {
    }

    public static function &getInstance() {
        if (DatabaseConnection::$instance == null) {
            DatabaseConnection::$instance = new DatabaseConnection();
        }
        return DatabaseConnection::$instance;
    }
}

$mysql_query("...", DatabaseConnection::getInstance());

The & means passing by reference, so there would be only one instance of the database object even if it is used in several different files, classes or functions. See http://php.net/manual/en/language.references.pass.php for more information.

Jakob Pogulis
  • 960
  • 1
  • 7
  • 18
  • This definitely answers my question. The latter is what I expected to do. However, it seems so unclean. Having to resort to a static variable to hold the instance of the class. Oh well. Thank you! – Steffan Long Mar 30 '13 at 06:23
  • The Singleton design pattern is well known, although disliked by many since it is, as you say, so unclean. – Jakob Pogulis Mar 30 '13 at 06:24
  • @SteffanLong in case you copied the code, there was a stray exclamation mark in the getInstance() method, although it is fixed now. – Jakob Pogulis Mar 30 '13 at 06:26
  • Singleton is an anti-pattern because its just another form of global state. – Yang Mar 30 '13 at 06:31
  • @metal_fan I disagree, just because something is a form of global state does not make it an anti-pattern. If that'd be the case we'd need to redefine what a pattern is. Singleton guarding mechanisms to your global object, it's not just there for everyone to modify as they wish, you can put constraints. Often in MVC applications and bigger applications you'll need to access some sort of application registry containing dependencies - if you don't you'll be forced to pass the object on in every part of the chain be it using constructors or by method invocation. – Centril Mar 30 '13 at 08:27
  • @Centril have you ever heard about Unit-testing and Mocking? I think you are talking about MVP application, not MVC, because in MVC applications the problems like you've described above could be solved using factory and lazy initialization (+and maybe DiC). (Just look at how `ZF2` does it). – Yang Mar 30 '13 at 12:12
  • 1
    @JakobPogulis The first option (passing it to the constructor) is _much_ better since it will let you easily mock, and test your program by passing a 'fake' data-base connection that will let you isolate problems later. – Benjamin Gruenbaum Mar 30 '13 at 12:27
  • I have heard about and use extensively the all of the above. And I am talking about MVC, not MVP... Yes, you could and mostly should use factory and lazy initialization and Dependency injection - but you'll end up passing objects around like crazy - either via constructors or setters, unless you pass the "application" object itself. Besides - a database handle should not be created by factory more than once (unless you're a self saboteur). – Centril Mar 30 '13 at 12:31
  • 1
    -1: singleton is an antipattern, that introduces global state in an application. Also, since PHP5.0, passing objects by reference is harmful. – tereško Mar 30 '13 at 12:32
  • Care to explain why? you're just stating it as a fact without any explanation. Granted the Single Responsibility Principle, then you could have several layers of abstraction... An object/class that has the responsibility of e.g placing an order ( there's no "and" in there and thus still single responsibility ) which can be broken down to many steps internally. It is not too uncommon to end up with a stack depth of 10 method calls. What if you need some dependency state/object of the first level...? – Centril Mar 30 '13 at 12:48
  • To people talking about anti-pattern, the definitive place in hell if using Singletons, and what not. It might very well be true (as I stated) that Singletons are considered bad design. Although there are several cases when you're way past the design phase or your code is just too cluttered; introducing some other solution than Singleton might just not be worth the effort. Although in a theoretical world everyone would be returning to the design phase as soon as something doesn't make complete sense in a project. – Jakob Pogulis Mar 30 '13 at 16:30
0

Jakobs advice on using Singleton + aggregation is sound advice. To that I'd add Doctrine ORM/DBAL, http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html

Avoid coupling the singleton instance directly to your objects by using them inside the "Foo" class, but rather pass the singleton instance to the constructor. This way you have more decoupling and thus more freedom.

Centril
  • 2,224
  • 17
  • 28
  • Thanks for your advice. – Steffan Long Mar 30 '13 at 06:32
  • You're welcome. metal_fan:s answer is also great, Dependency Injection is what you should be using, but you'll probably need to store application dependencies in a sort of registry for your app - I'd store the EntityManager or DB-handle there and then implement some sort of Application -> getInstance() -> getDependency( "DB" ). Alternatively, if you decide to use MVC, you could always pass DB-handle to your controller "behind the sceen". Btw, if you've the privilige of using PHP5.3, use Late static binding: http://stackoverflow.com/questions/5152085/php-late-static-binding-in-singleton – Centril Mar 30 '13 at 06:44
  • It may very well be so, but just stating "singleton is NEVER good advice" is neither. If you're making such a claim, at least back it up. My view on singleton is that it should be avoided - that it is a necessary evil sometimes. My view of it is pragmatic. Besides, in my advice I also brought up decoupling & Doctrine... – Centril Mar 30 '13 at 13:05
  • I upvoted your post. I don't know why it was downvoted. – Steffan Long Apr 03 '13 at 23:18