SitePoint Sponsor

User Tag List

Results 1 to 12 of 12
  1. #1
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)

    Database as a singleton?

    For me there is no apparent difference between:

    Code:
    $db = db::getInstance();
    $db->query('SELECT...');
    and

    Code:
    db::query('SELECT...');

    apart from the extra line and (albeit tiny) extra memory needed for the extra defined variable. I can see that if you needed two instances of the database class, that it would be useful but I can't think of a single time when I'd need to do this. I'll never need to connect to more than one database.

    Is there anything wrong with creating a map to the mysqli functions like this?

    Before anyone starts an argument about rewriting inbuilt functions, there are several reasons I need to abstract them:

    -Automated error handling for all queries
    -My query function has logic for dealing with results from a stored procedure so I can just do $result = db::query('call stored_procedure();'); and it acts like a normal select.
    -The query function accepts an array and does replacements on:

    PHP Code:
    foreach ($params as $key => $value$query str_replace('%' $key '%'self::escape($value), $query); 
    I can then do a query like db::query('SELECT * from users WHERE username = %0% and password = %1%', array($username, $password));

    n.b. The reason for allowing name value pairs is for multiple replacements. When joining lots of tables where the foreign key is indexed it's significantly faster if you add "AND fk=value" to the join line and the where line (in mysql at least)


    Now, back to my question. From a design point of view, is this the best way of accessing my mapped database functions throughout the script.

    I've read a little about dependency injection but this seems like overkill to me. So much has to be done from an efficiency and development time alone it doesn't seem worth it. I'm open to comments on this as perhaps i'm missing something vital but the overheads of this seem to heavily outweigh the mediocre gains.

    My main thoughts are mapping the functions in a static class going to cause problems down the road? Would the singleton pattern be better? If so why?

    Should I do something else entirely?

  2. #2
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Any time you use a static function you are de facto hard coding. I don't like either your Singleton pattern or a bunch of static calls.

    What about testing? How can you pass a different database for testing? What about a mock object or other simulated database connection for faster tests?
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  3. #3
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    I realise it's hard coding. But is this really a problem? I *know* I'm always going to be using mysql (i'd have hundreds of queries to optimise again for a different database due to the slight differences between them). I don't have any database abstraction for the sake of using different databases as this is never going to happen. If it did, rewriting the database class would be about 1% of the total time of re-writing/optimising the queries.

    When I'm testing I also want to be testing the queries work as expected and as efficiently as possible. For database I would never use a mock object. For anything that doesn't interact with the outside world directly I can see the point but for the database (or for anything reliant on file operations) I want to be dealing with realistic data in my tests.

    For switching to a development database it's a simple as changing the db::connect() line to the development database criteria.

  4. #4
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    $db = db::getInstance();
    $db->query('SELECT...');
    ...is slightly less evil than....

    Code:
    db::query('SELECT...');
    only because if call db::getInstance() once and then pass the instance around, the later would be seriously hardcoded.

  5. #5
    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 sweatje View Post
    What about a mock object or other simulated database connection for faster tests?
    For real queries is mock object absolutely useless, because you need data. And connection can be tested with mysqli_connect_error() or similar function.

  6. #6
    SitePoint Addict webaddictz's Avatar
    Join Date
    Feb 2006
    Location
    Netherlands
    Posts
    295
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Mastodont View Post
    For real queries is mock object absolutely useless, because you need data. And connection can be tested with mysqli_connect_error() or similar function.
    I agree on the uselessness of a mock when it comes to actually querying the database, but that's because mocks are solely for testing purposes, nothing more nothing less, so that's kind of implied. Now, sweatje (as always) has a very valid point: the result of hard coding the class' coupling you make your own code impossible to test.

    The way I see it, however, is that the inability to test is merely a side effect of a deeper problem, namely throwing basic OO principles such as polymorphism out the window.

    Quote Originally Posted by TomB View Post
    I *know* I'm always going to be using mysql (i'd have hundreds of queries to optimise again for a different database due to the slight differences between them). I don't have any database abstraction for the sake of using different databases as this is never going to happen.
    It's not about switching to a different database vendor. I've always disliked that example when explaining polymorphism, because switching to a different vendor will take more than simply rewriting your classes. It's about adding or changing behaviour of the specified class. When hardcoded, you can not change the behaviour of a class without modifying it, or using one of those ugly setInstance( ) hacks.

    Using a Singleton for anything is a strict violation of the Polymorphic Open/Closed Principle. That's not just purist talk: it'll make your life a hell of a lot easier of you adhere to that principle. Altering or extending a class' behaviour should not be done in the class itself, but rather by another class that has the same interface, or extending the class to implement that new behaviour. Using Simpletons (pun intented) you're throwing away decent OO strategies.

    But hey -- if it works for you: good on you!

    Quote Originally Posted by TomB View Post
    I've read a little about dependency injection but this seems like overkill to me. So much has to be done from an efficiency and development time alone it doesn't seem worth it. I'm open to comments on this as perhaps i'm missing something vital but the overheads of this seem to heavily outweigh the mediocre gains.
    Then read more (I know I have). Yes, there is a performance overhead in using a Dependency Injection Container, but then, we're talking about software in a time where servers are cheap and people are expensive. Using a DIC, you'll generally cut back on the time that you use debugging, maintaining or extending your application, simply because you only have to write a simple class that extends functionality and "plug it in". The gains in time, eventually, are more than mediocre and outweigh the performance heavily.

    Using a DIC and adhering to the commonly accepted OO principles will save you time, because you'll write better code. It's a simple question of hacking vs. structuring an application, if you ask me.

    Ah well, that's just how I feel about things
    Yes, I blog, too.

  7. #7
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,052
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    I think your overcomplicating things. The object used to directly communicate with the database should be separate from the object to abstract the queries and collect result sets. They are two very different responsibilities which should be represented in two separate classes.

    PHP Code:
    $db = new Connection('user','pass','db_name','password');
    $manager = new QueryManager($db);
    $result $manager->query('SELECT * FROM users id = ?',array(3)); 
    I don't really see the purpose of any static methods or properties in this instance.

  8. #8
    SitePoint Enthusiast
    Join Date
    Dec 2003
    Location
    norway
    Posts
    61
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    As i understand, dendency injection could be something like:

    $theObject = new Test();

    $theObject->setDatabase($databaseConnection);


    And in the class:

    public function setDatabaseConnection($databaseConnection) {
    $this->_databaseConnection = $databaseConnection;
    }

    So it could be rather easy to implement actually..

  9. #9
    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 TomB View Post
    I'll never need to connect to more than one database.
    I've said that once, and were wrong. Might not be the case for you, but then it might. Those things come up when you try to use your code in a bigger scale; Say when integrating with other applications, or when adding new layers to your application.

    The database is probably one of those places where you can argue both ways, but a lot of people have simply made it a principle to avoid global stateful objects all together, because that means that there is only one way to provide dependencies, thereby simplifying the overall application design. It also means that you don't have to make hard choices in the borderline cases. Dogmatic? Perhaps so ..

    Quote Originally Posted by danman View Post
    As i understand, dendency injection could be something like (...)
    Yes, or simply:

    PHP Code:
    $theObject = new Test($databaseConnection); 
    It's not magic.

  10. #10
    SitePoint Addict webaddictz's Avatar
    Join Date
    Feb 2006
    Location
    Netherlands
    Posts
    295
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by oddz View Post
    I think your overcomplicating things. The object used to directly communicate with the database should be separate from the object to abstract the queries and collect result sets. They are two very different responsibilities which should be represented in two separate classes.
    Agreed. Rereading my own post, I seem to promote the usage of a DIC as the one and only single best solution. However, it's not. If your application doesn't have a lot of dependencies, it'll be overkill as using a DIC doesn't do that much extra if it's easy to keep track of dependencies and probably even makes your software's architecture less transparant.

    The reason I wrote about DIC's is because TomB asked about it, not because it's always the best or only option (although it is my favorite solution for passing stuff around).

    Quote Originally Posted by oddz View Post
    PHP Code:
    $db = new Connection('user','pass','db_name','password');
    $manager = new QueryManager($db);
    $result $manager->query('SELECT * FROM users id = ?',array(3)); 
    I don't really see the purpose of any static methods or properties in this instance.
    This is a perfectly viable option and there is not a need for static methods nor properties, as oddz stressed. However, this (creating the connection) will usually be done in a bootstrap file, whereas the actual querying tends to happen in the infrastructural sublayer of the model layer. I think TomB's main question is: how do I get the $db object from bootstrap to the object that actually uses it.

    There are several options, and several associated design patterns: first, you can put it in a box and pass that box around, till the dependant object is instantiated, pull it out of the box and pass it along (this is called the Registry pattern). A lot of objects will be depending on the Registry object.

    Another option is to have a box that you don't put the actual objects in, but rather objects that know how to create the other objects (which are known as Factories). When you ask this box for the database and it didn't instantiate it before, it'll ask the factory to do so and pass the result back. You pass this box along too. A lot of objects will be depending on the Service locator.

    The third option is using a Dependency Injection Container. There's a box, you put stuff in or you configure how to create that stuff, depends on implementation. You ask the DIC for the first and most important object of your application, and it will instantiate that object for you, with all of the objects' dependencies and the dependency's dependencies and so forth. The result is that only the runtime factories of your application know about the DIC, the rest is "blissfully ignorant", they just know they receive their dependencies and they don't care who gave it to them.

    The fourth option is the one you've described in the topic's start: using a Singleton. This means that you'll have an object that's shared in the global namespace, which means each and every object knows how to get that object. Although this sounds simple (and it is -- at first), there are quite a few problems with this approach: first and foremost, every object that needs the Singleton is sinfully aware of it's implementation *and* whereabouts.

    This all leads to the fact that there is no "box", which means you can't change implementation nor whereabouts of the object. The second problem is that your application's architecture isn't apparent: you can only find an object's dependency by staring at the code and I'd rather see the dependencies in the API documentation. That alone is reason enough to avoid the pattern, for me.

    Quote Originally Posted by danman View Post
    As i understand, dendency injection could be something like:
    $theObject = new Test();
    $theObject->setDatabase($databaseConnection);

    And in the class:
    public function setDatabaseConnection($databaseConnection) {
    $this->_databaseConnection = $databaseConnection;
    }
    So it could be rather easy to implement actually..
    Well, I think there is a problem in the name of Dependency Injection. There is a *huge* difference between Dependency Injection and using a Dependency Injection Container. Dependency Injection itself is just good practice, such as illustrated above by danman, whereas the incorperation of a Dependency Injection Container is actually an implementation which simplifies the incorperation of aforementioned good practise. If I had any authority on the matter (which I obviously don't), I'd rename Dependency Injection to Dependency Passing, I think that'd save a lot of confusion.
    Yes, I blog, too.

  11. #11
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,052
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    Quote Originally Posted by webaddictz
    If I had any authority on the matter (which I obviously don't), I'd rename Dependency Injection to Dependency Passing
    or… composition

    I don't really mind using static methods and properties so long as they have a very specific purpose and aren't cluttered across the entirety of the application. For example, I use a static method to set connection object on my ActiveRecord class.

    ActiveRecord::setConnection($db);

    However, that class is the only one that is tightly bound to the connection. All other classes are passed the connection through composition. I felt this was necessary because it eliminated the need to pass the connection constantly. The connection really only needs to be in one place because all communication between the database and abstraction of SQL happens through the ActiveRecord base class.

  12. #12
    SitePoint Addict webaddictz's Avatar
    Join Date
    Feb 2006
    Location
    Netherlands
    Posts
    295
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by oddz View Post
    or… composition
    Haha, I've never really looked at it that way, but you are definitely right.

    Quote Originally Posted by oddz View Post
    I don't really mind using static methods and properties so long as they have a very specific purpose and aren't cluttered across the entirety of the application. For example, I use a static method to set connection object on my ActiveRecord class.
    My direct arguments are not against using static variables or methods, per se. It's more the Singleton design pattern that I dislike. Then again, I have problems with using statics altogether as well, but that's mostly purist talk. Using it the way you demonstrated (using a ::setDatabase( )) is not by far as bad as having the ActiveRecord class do a call to Database::getInstance( );. Why? You can still use another implementation and set it to the ActiveRecord class, and it definitely shows on the API.

    I'd say this usage of static is not half bad. If I were to use static, this would be the way.

    Quote Originally Posted by oddz View Post
    However, that class is the only one that is tightly bound to the connection. All other classes are passed the connection through composition. I felt this was necessary because it eliminated the need to pass the connection constantly. The connection really only needs to be in one place because all communication between the database and abstraction of SQL happens through the ActiveRecord base class.
    By using a DIC you'll essentially accomplish the same: you don't have to pass around stuff any more, it's just there and only for the objects that really need it.
    Yes, I blog, too.


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
  •