SitePoint Sponsor

User Tag List

Results 1 to 22 of 22
  1. #1
    SitePoint Evangelist -T-'s Avatar
    Join Date
    Jun 2002
    Posts
    444
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    DB manager as singleton, why not?

    Is there any reasons other then support for multiple databases to not code a database manager as a singleton in php?

    Since there is no threading issues with php I can't see any other reason. Can you?
    chrome is a wrapper that combines a browser with spyware

  2. #2
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,011
    Mentioned
    56 Post(s)
    Tagged
    0 Thread(s)
    That's what I do. Multithreading does occur in PHP, but not within a given script execution. Opening multiple db connections for one script seems wasteful.

  3. #3
    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)
    When testing code, it can be useful to be able to have multiple database connections.

    That said, the main reason for avoiding singletons is non-technical. A singleton introduces dependencies in the code that uses it. This is of course essential (you need the database connection, no matter how you put it), but it is not apparent, when you use a global symbol to access it with. Thus it makes it slightly harder to understand the programs flow. Another problem with it, is that it mixes up two different responsibilities in one place. That again obscures the working of the program, making it harder to understand.

    I like this article, discussing the subject.

  4. #4
    <?php while(!sleep()){code();} G.Schuster's Avatar
    Join Date
    Mar 2007
    Location
    Germany
    Posts
    428
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    PHP Code:
    $db DBMan::getDB('mysql''host''user''pass''db'); 
    isn't any harder to understand than
    PHP Code:
    $db = new mysqli('host''user''pass''db'); 
    And the ability to open multiple connections isn't any problem with a singleton registry.
    OK, what could be a little bit bad would be to open the same database with exactly the same config - but I see asolutely no reason to to that - even not in test cases.
    For all other cases just store the connection in an associative array where the key is a hash of the config.

  5. #5
    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 G.Schuster View Post
    PHP Code:
    $db DBMan::getDB('mysql''host''user''pass''db'); 
    isn't any harder to understand than
    PHP Code:
    $db = new mysqli('host''user''pass''db'); 
    No, that isn't a problem, if you access the singleton only at the top level scope of your application. But consider these:

    PHP Code:
    class Foo {
      protected 
    $db
      
    function __construct(DatabaseConnection $db) {
        
    $this->db $db;
      }
      function 
    doStuff() {
        
    $this->db->query(...);
      }

    PHP Code:
    class Bar {
      protected 
    $db
      
    function __construct() {
        
    $this->db Database::getInstance();
      }
      function 
    doStuff() {
        
    $this->db->query(...);
      }

    Foo makes its dependencies explicit. Bar hides them.

  6. #6
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    No, that isn't a problem, if you access the singleton only at the top level scope of your application. But consider these:

    PHP Code:
    class Foo {
      protected 
    $db
      
    function __construct(DatabaseConnection $db) {
        
    $this->db $db;
      }
      function 
    doStuff() {
        
    $this->db->query(...);
      }

    PHP Code:
    class Bar {
      protected 
    $db
      
    function __construct() {
        
    $this->db Database::getInstance();
      }
      function 
    doStuff() {
        
    $this->db->query(...);
      }

    Foo makes its dependencies explicit. Bar hides them.
    Why to bother yourself with $this->db->query ... ???
    PHP Code:
    class Bar {
      function 
    __construct() {
        
    // some initialization
      
    }
      function 
    doStuff() {
        
    $result DB:Connect()->query(...);
      }

    And I saw somewhere on WWW yet simpler
    PHP Code:
    $result db()->query(...); 

  7. #7
    <?php while(!sleep()){code();} G.Schuster's Avatar
    Join Date
    Mar 2007
    Location
    Germany
    Posts
    428
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What hinders you to pass a singleton to the Bar-constructor?
    I still see no difference when comparing those:
    PHP Code:
    $db = new mysqli();
    $foo = new Foo($db);

    class 
    Foo {
      protected 
    $db
      
    function __construct(DatabaseConnection $db) {
        
    $this->db $db;
      }

    PHP Code:
    $db DBMan::getDB();
    $foo = new Bar($db);

    class 
    Bar{
      protected 
    $db
      
    function __construct(DatabaseConnection $db) {
        
    $this->db $db;
      }

    Comparing your Foo/Bar example is really comparing apples and oranges (as you previously stated ) as you moved the dependancy at your will - not because it was required in any way.

    And as you mentioned the scope - where do you set the $db that Foo depends on?
    Right! At the top level where you can equally use a statically fetched singleton instance.

    OK, while writing these lines I recognized that we also may be discussing different things...
    I don't see singletons the way that I always hav to use Singleton::getInstance() whenever I want to access it - I see it more as a way to restrict multiple instances to keep memory consumption and even confusion to a low level.
    This doesn't hinder me to still use it as a regular object and pass it to any dependant class/method/whatever I like.
    Do we mean/think the same? If not, please elaborate a little where you see any differences.

  8. #8
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,042
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    Bar shouldn't be tightly coupled to DB. Instead use composition.

    PHP Code:
    class Bar {

      private 
    $db;

      public function 
    __construct(DB $db) {
        
    $this->db $db;
      }

      public function 
    doStuff() {
        
    $result $this->db->query();
      }

    }

    $bar = new Bar(DB::getInstance()); 
    The only code I hate more than my own is everyone else's.

  9. #9
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by oddz View Post
    Bar shouldn't be tightly coupled to DB. Instead use composition.

    PHP Code:
    class Bar {

      private 
    $db;

      public function 
    __construct(DB $db) {
        
    $this->db $db;
      }

      public function 
    doStuff() {
        
    $result $this->db->query();
      }

    }

    $bar = new Bar(DB::getInstance()); 
    But then the class that creates the Bar object is tightly coupled with the database class... Object instantiation is best pushed high up in the application, into a place that only deals with instantiation, like in a DI.

  10. #10
    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 G.Schuster View Post
    Do we mean/think the same? If not, please elaborate a little where you see any differences.
    Yes, we're talking about two different things here

    A Singleton has two characteristics; It's a factory and it's a way to access an object. The former is no different from instantiating an object with new, since essentially the new keyword is just a static method on the class. (It's not obvious with PHP, but it's actually implemented that way in many other languages). I have no problem in replacing one static factory with another.

    The problem with the singleton pattern is in its other aspect; Providing a (global) means to access a variable. So as long as you only ever use the singleton method from the top-level scope of your application, then fine. But that's not how people use it in practise.

  11. #11
    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 Mastodont View Post
    Why to bother yourself with $this->db->query ... ???
    Agreed - They are essentially interchangeable; It's all just variations of a global variable.

  12. #12
    SitePoint Evangelist -T-'s Avatar
    Join Date
    Jun 2002
    Posts
    444
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    When testing code, it can be useful to be able to have multiple database connections.

    That said, the main reason for avoiding singletons is non-technical. A singleton introduces dependencies in the code that uses it. This is of course essential (you need the database connection, no matter how you put it), but it is not apparent, when you use a global symbol to access it with. Thus it makes it slightly harder to understand the programs flow. Another problem with it, is that it mixes up two different responsibilities in one place. That again obscures the working of the program, making it harder to understand.

    I like this article, discussing the subject.
    Thanks, nice article. I'm a little concerned though. To me it looks like, if you don't use a singleton in this case, you will have to pass the database instance through the constructor (or a method) of every class you load. Or use a super global, either being non desirable.

    Even if you use the factory method mentioned in the article, there is no way to prevent multiple instances being made. So if you are in a situation where there are many chefs, several instances will most likely be loaded

    And in the rare case that you need to have a second connection to a database, you have the __clone() method in php that will allow you to make a deep copy of the instance
    chrome is a wrapper that combines a browser with spyware

  13. #13
    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 -T- View Post
    I'm a little concerned though. To me it looks like, if you don't use a singleton in this case, you will have to pass the database instance through the constructor (or a method) of every class you load. Or use a super global, either being non desirable.
    A global would be no improvement over singleton. (In fact, I'd argue that a Singleton is a global). Yes, you'll have to pass the dependency explicitly in the constructor, but there are two things to be said about that. The first is, that while people initially have a tendency to think of it as a big problem, it usually isn't that big a deal. The second is, that you can abstract it away in a factory. If you take the abstraction far enough, you'll get a generic factory, also known as a dependency injection container. These can work almost automatically, so you'll end up doing less manual labour than with a singleton.

    Quote Originally Posted by -T- View Post
    Even if you use the factory method mentioned in the article, there is no way to prevent multiple instances being made. So if you are in a situation where there are many chefs, several instances will most likely be loaded
    Presumably, you would have some sort of quality control of the code base. I take it that you don't let any random Joe write and execute code on your system? So what you would do to prevent such unintended behaviour, would be to grep the code for any direct instantiation of a class that is supposed to be shared. Eg. look for "new DatabaseConnection" in the application code. Any such occurrence would be a bug.

  14. #14
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have a class with static functions for my DB.
    Since most the code runs on the same "connection", I can easily use it like:
    PHP Code:
    DB::connect('user','pass','db','host');
    $data DB::selectRows('SELECT * FROM foo'); 
    BUT, I can assign a handle to my class, so if I want to use some other connection, I could do this:
    PHP Code:
    DB::connect('user','pass','db','other_host','link_id');
    $data DB::selectRows('SELECT * FROM foo','link_id'); 
    or
    PHP Code:
    DB::connect('user','pass','db','other_host','link_id');
    DB::selectLink('link_id');
    $data DB::selectRows('SELECT * FROM foo');
    DB::selectLink(); // Back to default 

    The +
    - No need to declare my DB every time, or get a handle to it.
    - Always the same in all my system
    - 99% of the time I only need the default handle (no link_id)
    - The "connection" is actually an instance of your class (from previous examples), since my default 'link', reads from 1 out of 20 possible servers, and writes to 1 of the 3 master servers.
    - No variables to pass to functions / classes all over, so cleaner code.
    - No need to connect to the server when you call "DB::connect", but only the first time something needs to use that connection 'link'. This means that if you have 20 databases, you just set up the DB::connect in your configuration file, and if no DB connections are used on your page, no connections are made.

    The -
    - People hate the "global" way this works (as in, you have to use DB:: everywhere, no FOO:
    - When you have multiple links, you must know what link to use from inside objects using it (might not be such a bad thing, but when you have 20 places that need this link, and then you re-factor the DBs, you might need to change your 'links' if you didn't plan ahead for it/ do it right)
    - I don't like the: "DB::selectLink('link_id');" and "DB::selectLink();" part.


    Hope this helps or gives some ideas.

  15. #15
    SitePoint Evangelist -T-'s Avatar
    Join Date
    Jun 2002
    Posts
    444
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    A global would be no improvement over singleton. (In fact, I'd argue that a Singleton is a global). Yes, you'll have to pass the dependency explicitly in the constructor, but there are two things to be said about that. The first is, that while people initially have a tendency to think of it as a big problem, it usually isn't that big a deal. The second is, that you can abstract it away in a factory. If you take the abstraction far enough, you'll get a generic factory, also known as a dependency injection container. These can work almost automatically, so you'll end up doing less manual labour than with a singleton.

    Presumably, you would have some sort of quality control of the code base. I take it that you don't let any random Joe write and execute code on your system? So what you would do to prevent such unintended behaviour, would be to grep the code for any direct instantiation of a class that is supposed to be shared. Eg. look for "new DatabaseConnection" in the application code. Any such occurrence would be a bug.
    You might be right here. According to Steve Yegge (http://steve.yegge.googlepages.com/s...sidered-stupid) what I'm doing is premature optimization. But I'm thinking there is something else going on too.

    The way I see the database manager is as a sub system. A little black box I stick a query into and get a result returned. The returned result is not an instance, only a multidimensional assoc array or the like containing the rows a columns of the result. It's the job of the querying class to call the factories needed to generate the instances.

    I see the db manager and all the classes it uses to present me with an answer to my query as ... I guess a daemon would be the closest thing here.

    And with this in mind, I can open a connection to the database at the start of script execution and keep it open until execution is done. As this is a server with short lived scripts it shouldn't be an issue

    A factory pattern doesn't really apply in this case (maybe inside the black box, but that's invisible to the outside), as it is only a single instance to work with. It's not a combination of several

    Am I really wrong in thinking like that for a database manager?
    There seems to a be general agreement to singleton being a good thing for a logging class, but I fail to see the difference in this case. Could you please explain?
    chrome is a wrapper that combines a browser with spyware

  16. #16
    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 -T- View Post
    The way I see the database manager is as a sub system. A little black box I stick a query into and get a result returned. The returned result is not an instance, only a multidimensional assoc array or the like containing the rows a columns of the result. It's the job of the querying class to call the factories needed to generate the instances.
    The thing you're objecting to here (and excuse me for putting words in your mouth), is that your application code shouldn't need to know the dependencies of the components that it works with. Eg. if you have a FooMonger, that uses a BarMonger, it shouldn't need to know if the BarMonger depends on a DatabaseConnection or not. And I agree; You wouldn't want a class to become a "distribution channel", that only has a dependency in order to present it to some other class.

    Dependency injection is not at odds with this. The main premise for DI is that your application consists of two different categories of objects; There are those that are relatively long lived and tend to be the only instance within the applications runtime (shared objects) and then there are short lived objects (transient objects), such as database result (Even if it's technically an array, I'll conceptually call it an object). Transient objects are created deep within your application, at runtime. In contrast, shared objects tend to be created once and typically at the beginning of your program (Though a Singleton or a factory can defer the creation until the first usage).

    The transient objects must have their dependencies available by the creator, but for shared objects, you can separate your application into a creation phase and a runtime phase. In the creation phase, you resolve any (shared) dependencies between objects and wire them up. Eg. When you create your FooMonger, you pass it a BarMonger. Thus the FooMonger needn't know about the BarMongers dependency on DatabaseConnection, because it is externalised. As mentioned, all of this can be automated to a rather far extend.

    You're still left with the transient objects of course. You can deal with this by trying to avoid letting transient objects have too many shared dependencies. This has some beneficial side effects, in that it tends to make separate stateful parts of your program from parts with side effects. Eg. your transient objects represent state, while the side effects are confined to shared objects.

    Quote Originally Posted by -T- View Post
    There seems to a be general agreement to singleton being a good thing for a logging class, but I fail to see the difference in this case. Could you please explain?
    Yes, I'm not entirely sure where that comes from, but I've seen it as well. I think the general idea is that logging isn't part of the business logic, and therefore doesn't follow the same rules. That it exists in a different layer of abstraction. I'm not buying it completely, but I do acknowledge that it can be quite hard to avoid global symbols for debugging and such on. Some times, theory and practise don't fit neatly together.

  17. #17
    SitePoint Evangelist -T-'s Avatar
    Join Date
    Jun 2002
    Posts
    444
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is starting to make sense to me now Thanks

    Just to make sure, lets put some code up for this and see what happens\

    This is off course very simplified. But essentially, instead of using singletons you suggest that using a list of instances created in the top class (bootstrap in this case) and pass them down through the constructor for the classes which needs them. Then to prevent a big list of parameters in the constructor, or method, we wrap this in an object wrapper class.
    PHP Code:
    public class BucketObjectWrapper()
    {
      private 
    Database DBMgr;
      private 
    Config Conf;
      ...
      private 
    ErrorHandler Err;

      public 
    ButcketObjectWrapper()
      {
        
    // initialize all instances needed
      
    }
    }

    public class 
    Bootstrap
    {
      private 
    BucketObjectWrapper Bucket;

      public 
    void Bootstrap()
      {
        new 
    FrontPage(Bucket);
      }
    }

    public class 
    FrontPage
    {
      private 
    BucketObjectWrapper Bucket;

      public 
    FrontPage(BucketObjectWrapper Bucket)
      {
        
    this->Bucket Bucket;

        
    // load a widget?
        
    new Widget(Bucket);
      }
    }

    new 
    Bootstrap(); 
    Wouldn't this just make this instance a global in all but name, and it's not apparent from the code that you are depending on the database manager.

    That said, dependencies should be part of the class documentation >_>
    chrome is a wrapper that combines a browser with spyware

  18. #18
    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 -T- View Post
    BucketObjectWrapper
    Your BucketObjectWrapper class is essentially a registry. That's another way of handling it, but I prefer DI. With DI, your code would look something like this:

    PHP Code:
    class Widget {
      private 
    DatabaseConnection $db;
      function 
    __construct(DatabaseConnection $db) {
        
    this->db $db;
      }
    }

    class 
    FrontPage {
      private 
    Widget $widget;
      function 
    __construct(Widget $widget) {
        
    this->widget $widget;
      }
    }

    class 
    Bootstrap {
      function 
    run() {
        
    $db = new DatabaseConnection();
        
    $widget = new Widget($db);
        
    $fp = new FrontPage($widget);
        
    $fp->doStuff();
      }
    }

    $b = new Bootstrap();
    $b->run(); 
    The point is that you pass the concrete dependency to the component that needs it. This has the effect of pulling the creation of all shared objects up on the top level. It's extremely simple, which is why it can be a bit hard to grasp at first.

    Quote Originally Posted by -T- View Post
    Wouldn't this just make this instance a global in all but name, and it's not apparent from the code that you are depending on the database manager.
    No, you're conflating symbol with value. A variable is a symbol that refers to some value. The problem with global variables is that the symbol has global scope; It's not a problem that the value itself is globally unique. In other words; No matter how you cut it, there should only be one database connection in your application (Or at least - Let's assume that this is the case), but there is a difference between all your code using the same symbol to refer to this instance, or different components using local symbols.

    A registry (the design you've depicted) differs from using a global variable in that the context could pass a different registry. In other words, the context controls the scope. So in your example, you could create a BucketObjectWrapper, that didn't have a real database connection. Or you could create two different TableGateways, both referring the same table, but in different databases. Obviously, DI allows the same thing.

  19. #19
    SitePoint Evangelist -T-'s Avatar
    Join Date
    Jun 2002
    Posts
    444
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    PHP Code:
    class Widget {
      private 
    DatabaseConnection $db;
      function 
    __construct(DatabaseConnection $db) {
        
    this->db $db;
      }
    }

    class 
    FrontPage {
      private 
    Widget $widget;
      function 
    __construct(Widget $widget) {
        
    this->widget $widget;
      }
    }

    class 
    Bootstrap {
      function 
    run() {
        
    $db = new DatabaseConnection();
        
    $widget = new Widget($db);
        
    $fp = new FrontPage($widget);
        
    $fp->doStuff();
      }
    }

    $b = new Bootstrap();
    $b->run(); 
    If I read your code correct, all you are doing is passing the class instances to the lower levels as params. Lets say both the widget class and the front page class depends on the db. Then you get something like this

    PHP Code:
    // left out code

    class Bootstrap {
      function 
    run() {
        
    $db = new DatabaseConnection();
        
    $widget = new Widget($db);
        
    $fp = new FrontPage($widget$db);
        
    $fp->doStuff();
      }

    now lets say you have a config class, an error handler and .. I don't know foo and bar classes that needs to be passed to front page too

    PHP Code:
    // left out code

    class Bootstrap {
       function 
    run() {
         
    $DB = new DatabaseConnection();
         
    $Widget = new Widget($DB);
        
    $Err = new ErrorHandler();
        
    $Conf = new Config();
        
    $Foo = new Foo();
        
    $Bar = new Bar();
         
    $FP = new FrontPage($Widget$DB$Err$Conf$Foo$Bar);
         
    $FP->doStuff();
       }
     } 
    Now that isn't very pretty, and should be wrapped in an object to pass it through, right? Which is why I slapped the whole shebang into a object wrapper

    If I got this right, all classes that is supposed to be only created once is created on top level and then passed down. No matter how many of them there are?
    chrome is a wrapper that combines a browser with spyware

  20. #20
    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 -T- View Post
    If I read your code correct, all you are doing is passing the class instances to the lower levels as params. (...) If I got this right, all classes that is supposed to be only created once is created on top level and then passed down. No matter how many of them there are?
    Yes.

    Quote Originally Posted by -T- View Post
    Now that isn't very pretty, and should be wrapped in an object to pass it through, right? Which is why I slapped the whole shebang into a object wrapper
    First off, I think people have a tendency to overestimate the problem. You only have to put the wiring code in one place, and you only really have to write it once. So as long as you only have a limited set of classes (say less than 50), I actually prefer that way.

    However, there is a different solution to it, which is Dependency Injection Containers. Basically, a container is a factory, which can be configured somehow. This means that instead of programming the wiring, you configure it. Most containers further use reflection to provide a default configuration, which means that you only have to configure manually, if you diverge from defaults. The way they work, is usually by looking at the typehints of constructors. For example:

    PHP Code:
    class Widget {
      private 
    DatabaseConnection $db;
      function 
    __construct(DatabaseConnection $db) {
        
    this->db $db;
      }
    }

    class 
    FrontPage {
      private 
    Widget $widget;
      function 
    __construct(Widget $widget) {
        
    this->widget $widget;
      }
    }

    $container = new bucket_Container(); 
    $fp $container->get('FrontPage'); 
    $fp->doStuff(); 
    The above code uses my own (rather simplistic) DI container, Bucket. There are other implementations available, which have a more sophisticated configuration apparatus. You can find links at the bottom of this page.

    Quote Originally Posted by -T- View Post
    now lets say you have a config class, an error handler and .. I don't know foo and bar classes that needs to be passed to front page too
    This is the beauty of a DI container. If the dependencies for a class changes, the container will notice it and provide the dependency transparently to the user. All you'd do is add the dependencies to the constructor of FrontPage, and the container will satisfy them.

    PHP Code:
    class FrontPage {
      function 
    __construct(Widget $widgetDatabaseConnection $dbErrorHandler $errConfiguration $confFooThingy $fooBarThingy $bar) {
      }
    }

    // Note that the client-code is unchanged:
    $container = new bucket_Container(); 
    $fp $container->get('FrontPage'); 
    $fp->doStuff(); 

  21. #21
    SitePoint Evangelist -T-'s Avatar
    Join Date
    Jun 2002
    Posts
    444
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks, now it makes sense to me. I had to read your DI bucket code a couple of times before I noticed how it stored the instances. And it's not that far from what you called a registry, except that it's dynamic

    And StdClass is new to me. Looked in the php.net and the pear.php.net docos and found nothing about it. Just a mention in the predefined classes list. Do you happen to know about a secret area in the php.net manual for this?
    chrome is a wrapper that combines a browser with spyware

  22. #22
    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)
    StdClass is very badly documented. That seems to be a tendency for object oriented features of PHP. It has been around for a long time though, and probably won't go away anytime soon. It's basically a class without any methods.

    The main difference between a container and a registry is in how you use it - Not in the implementation. You wouldn't have to pass the container itself in to the application, whereas a registry would be passed around.


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
  •