SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    Singleton Class Problems

    Hi all

    I am creating a site, which uses a singleton class called Site. Its general structure is like this:

    PHP Code:
    class Site {
      private static 
    $objInstance;

      private 
    $dbConn;

      private function 
    __construct () {
       
    $this->dbConn = new mysqli(HOSTUSERPASSNAME);
      }
    //function

      
    public function __clone() {
       
    trigger_error('Clone is not allowed.'E_USER_ERROR);
      }
    //function

      
    public static function getInstance () {
       if (!isset(
    self::$objInstance)) {
        
    self::$objInstance = new Site();
       }
    //if
       
    return self::$objInstance;
      }
    //function

      
    [...Other Functions...]

    }
    //class 
    There are lots of other objects as well to run the site, and at the moment I am creating a database connection in the constructor of each one, like this:

    PHP Code:
    $this->dbConn = new mysqli(HOSTUSERPASSNAME); 
    I quickly realised that this was a bad idea, because I quickly rack up the DB connection count. So I thought, why not just let the Site object create the DB connection, as it does at the moment, and have a function within it called getDBConn()?:

    PHP Code:
    public function getDBConn () {
       return 
    $this->dbConn;
      }
    //function 
    I replaced all the database connection creation lines in the other objects with this:

    PHP Code:
    $this->dbConn getDBConn() 
    ...where getDBConn() was a function which did this:

    PHP Code:
     function getDBConn () {
      
    $objSite Site::getInstance();
      return 
    $objSite->getDBConn();
     }
    //function 
    However, doing this, I got so many errors saying there are too many database connections open... I soon discovered that there was no longer only 1 instance of the Site object being created, as there should be with a singleton class, but one for each call to the getDBConn() function.

    Basically the problem I have is that I want to open the DB connection once, and have all the objects and functions use that connection. So, I somehow need to pass the mysqli object around between them, and I thought a singleton class that I already had would be perfect, but it seems to have 'broken' its functionality somehow. Does anyone have any ideas why, how I can fix it, or what alternatives are (I'd rather not use global variables).

  2. #2
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Stormrider View Post
    I'd rather not use global variables.
    A Singleton is global in scope. That makes it very similar to a global variable.

    Quote Originally Posted by Stormrider View Post
    Basically the problem I have is that I want to open the DB connection once, and have all the objects and functions use that connection. So, I somehow need to pass the mysqli object around between them ...
    The simplest way is to pass the dependency (the db connection) in the constructor of the object, which needs it. People come up with all sorts of schemes to avoid this simple, yet in most aspects, superior solution.

    The only downside to this pattern is, that the code which creates an instance needs to know which dependencies it has. If that becomes a problem, you can decouple the creation, using some kind of creational pattern, such as factory or a dependency injection container.

  3. #3
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    A Singleton is global in scope. That makes it very similar to a global variable.
    Similar, but not exactly the same.

    The simplest way is to pass the dependency (the db connection) in the constructor of the object, which needs it. People come up with all sorts of schemes to avoid this simple, yet in most aspects, superior solution.
    I have thought about that, but I can see problems with it too... mainly that some objects are created by the presentation layer, and I don't want to have to pass a DB connection through those calls, as well as the ones returned from a class.

    What I would like, is to try and fix my code above, and get it working that way. Do you know what the problem with it is?

  4. #4
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Stormrider View Post
    I have thought about that, but I can see problems with it too... mainly that some objects are created by the presentation layer, and I don't want to have to pass a DB connection through those calls, as well as the ones returned from a class.
    Anyway, it's actually fairly rare that you need to create new components at runtime. Often, you just need one instance, and so it could be passed from the outside.

    Assuming, that your presentation layer code needs some component, which depends on the database connection; You could pass this component to your presentation layer, rather than create the component inside the presentation layer. Then, your presentation layer never need to get an instance of the database connection.

    Quote Originally Posted by Stormrider View Post
    What I would like, is to try and fix my code above, and get it working that way. Do you know what the problem with it is?
    I don't see any problems with it -- It should work. Try pasting the code in entirety.

  5. #5
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    I pasted all the relevant bits... Is it something to do with one thing not passing by reference maybe? I really don't understand it.

  6. #6
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Stormrider View Post
    Is it something to do with one thing not passing by reference maybe?
    No.

    Quote Originally Posted by Stormrider View Post
    I pasted all the relevant bits...
    Those are just fragments of code. Produce a working example, as small as possible.

  7. #7
    SitePoint Wizard silver trophybronze trophy Stormrider's Avatar
    Join Date
    Sep 2006
    Location
    Nottingham, UK
    Posts
    3,133
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    It's OK, I managed to find another way around it. I changed the standalone getDBConn() function to:

    PHP Code:
    function getDBConn () {
      static 
    $dbConn;

      if (empty(
    $dbConn)) {
       
    $dbConn = new mysqli(HOSTUSERPASSNAME);
      }
    //if

      
    return $dbConn;
     }
    //function 
    which seems to work perfectly. Thanks for all your help & advice though


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •