SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 42
  1. #1
    gimme the uuuuuuuuuuu duuudie's Avatar
    Join Date
    Feb 2004
    Location
    Switzerland
    Posts
    2,253
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    the db object going global: bad idea?

    Hi there,

    I'm working on a OO project these days. No matter how respetful I am to scopes and OO compliancy, I am about to break the Object Model in order to make my DB object available to all my classes.

    The architecture of the project requires that object within other objects executing queries must well... execute requests. So I pass the db object as an argument of the object, which then must pass it to the object it composes, which then must pass it... you got the point.

    I was thinking about going the aggregation way (as opposed to objects composing other objects) but I must honestly say that the instanciation of my objects doesn't look good.

    So well... A static method would solve this a part of this problem but still... I'm not happy with it.

    I would like all my classes to have the ability to execute bits of code like this:
    PHP Code:
    $result $db->query($sql); 
    without having to worry about where $db comes from, where it has been instantiated, if it must be passed to a composed objects or what not.

    What do you think about it?

  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)
    you can make db a Singleton to solve your problem.
    PHP Code:
    class DatabaseConnection
    {
        function & 
    getInstance() {
            static 
    $instance=Array();
            if (
    count($instance) == 0) {
                
    $instance[0] =& new DatabaseConnection();
            }
            return 
    $instance[0];
        }

    PHP Code:
    class SomeClass
    {
        function 
    foo() {
            
    $db =& DatabaseConnection::getInstance();
            
    $result $db->query($sql);
        }


  3. #3
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Why the array?

  4. #4
    SitePoint Addict been's Avatar
    Join Date
    May 2002
    Location
    Gent, Belgium
    Posts
    284
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Jason (Sweatje) has answered this numerous times (with links to the PHP manual, SimpleTests and everything): The array is necessary because static variables cannot store references in PHP4.
    Per
    Everything
    works on a PowerPoint slide

  5. #5
    SitePoint Enthusiast
    Join Date
    Feb 2004
    Location
    Montreal
    Posts
    77
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Objects assigned to static variables are assigned by reference by default. I have never had trouble with the following Singleton patter:
    PHP Code:
    function &getInstance() {
        static 
    $instance NULL;

        if (
    $instance == NULL$instance = new Singleton;

        return 
    $instance;

    The same applies to variables passed by reference into functions:

    PHP Code:
    function pass_by_ref(&$obj) {
        
    $obj = &new Foo// Invalid $obj gets assigned by reference by default
        
    $obj = new Foo// Behaves as expected, obj is changed for the caller

    Anyway, if there is a flaw with this design please let me know!

    Oh, and on the subject of passing around a db object. I have had much success by designing my application as a series of filters having dependancies. What I do is a create my database object in the database filter and add it into the request object that propagates down the filter chain and eventually to an action. Yes, there is a need to again pass this object into non-filter classes. In practice, this is probably a good thing to do since it eliminates a dependancy on a static instanciation method for the database object. It also allows the database layer to be independant of the actual application.

    Consider this, you would like to create a database object proxy(?) that acts like a database but does some application specific stuff like logging queries and their results. If you tied yourself to a singleton pattern, each time you grabbed the instance, you would also have to check to see if you wanted to wrap the object in the database debugger or not. Much simpler is to allow a filter to perform the task that both depends upon and satisfies the database dependancy for other filters. That way, the database debugger filter (which could easily be considered a plugin) can modify the requests's database object to enable debugging. As a result, this change only needs to be queried and executed once per request.

    Anyway, hope this makes as much sense to you as it does to me. If not, just ask.

  6. #6
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by b1ind
    What I do is a create my database object in the database filter and add it into the request object...
    A request object often gets passed around almost everywhere but you need to guard against treating it as a convenient store for any old "global" values. It should stick to request responsibilities only.

    Perhaps a Registry might be the answer.

  7. #7
    SitePoint Enthusiast
    Join Date
    Feb 2004
    Location
    Montreal
    Posts
    77
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, perhaps request is a bad name. It is actually unrelated to $_REQUEST. The only things that I store in there are database template and user. It is mostly a convenience tool to provide a standardized way for filters to pass information to subsequent filters and actions.

  8. #8
    gimme the uuuuuuuuuuu duuudie's Avatar
    Join Date
    Feb 2004
    Location
    Switzerland
    Posts
    2,253
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    About the Singleton Pattern, how can it avoid the hassle of instantiating the db object in each class? You're still bind to write this:
    PHP Code:
    $db =& DatabaseConnection::getInstance(); 
    in each class...

    Making the object a global variable would simply make it available anywhere, which seems simpler to me, even though it's not 100% OO compliant.

    I still have a question: What the singleton pattern does is to avoid multiple and useless instantiations of a given object right?

    So in your example, I would include this line
    PHP Code:
    $db =& DatabaseConnection::getInstance(); 
    in each method querying the db?

    What about scope? If an object composes another object do add this line in the class related to the composed object and everything is fine?

  9. #9
    Employed Again Viflux's Avatar
    Join Date
    May 2003
    Location
    London, On.
    Posts
    1,127
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If passing around the global $db object is easy for you, and works, then go ahead and do that. The PHP police aren't going to arrest you.

    I handle this by using a singleton inside my datasource objects.

    For example, if I'm looking up a user, my UserDataSource class has a method called connect that is called up construction. If a connection to the database already exists, use that one. If not, it opens a new one.

  10. #10
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Viflux
    The PHP police aren't going to arrest you.
    It's not about enforcing obscure practices. It's about helping people to learn. Avoiding globals is one of the most basic things to learn.

  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 duuudie
    Making the object a global variable would simply make it available anywhere, which seems simpler to me, even though it's not 100% OO compliant.
    Simpler to write, but harder to debug. However - the databaseconnection may be one of the few things where you won't hurt your self too much by using a global. Still - it's a bad habit.
    Quote Originally Posted by duuudie
    I still have a question: What the singleton pattern does is to avoid multiple and useless instantiations of a given object right?
    That's another aspect of singleton. You don't have to actually connect to the database until your script needs it. If you use a global, you will have to connect even if your script won't be accessing the databse.

    Quote Originally Posted by duuudie
    So in your example, I would include this line
    PHP Code:
    $db =& DatabaseConnection::getInstance(); 
    in each method querying the db?
    Yes, but you could do it in the constructor if you're lazy. eg :
    PHP Code:
    class SomeClass 

        function 
    SomeClass() {
            
    $this->connection =& DatabaseConnection::getInstance(); 
        } 
        function 
    foo() { 
            
    $result $this->connection->query($sql); 
        } 


  12. #12
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi.

    I posted a big list of all the ways I could think of for handling this situation, but I've lost it. The list was missing dependency injection at the end, but I don't think DI is what you need here. Anyway, I cannot find the post now and Sitepoint only allows one search every ten seconds or so.

    Basically avoid globals for sure. Pass it around if you can, or at least pass a factory. If you really, really can't do that (I won't believe you btw ) then look at the Registry. Singletons can make a real mess of your testing, because you get test interference between each test case.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  13. #13
    Employed Again Viflux's Avatar
    Join Date
    May 2003
    Location
    London, On.
    Posts
    1,127
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by McGruff
    It's not about enforcing obscure practices. It's about helping people to learn. Avoiding globals is one of the most basic things to learn.
    At the risk of appearing like a newbie, which I am to PHP, why?

  14. #14
    Employed Again Viflux's Avatar
    Join Date
    May 2003
    Location
    London, On.
    Posts
    1,127
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    To expand on that...

    The language provides you, the programmer, the ability to make use of a global variable. And yet, it has become like witchcraft.

    I don't understand.

    Is there some advanced PHP techniques which require you not use global objects?

  15. #15
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry I didn't say *why* they are a bad idea. Here's a link from the C2 wiki: GlobalVariablesAreBad

  16. #16
    Employed Again Viflux's Avatar
    Join Date
    May 2003
    Location
    London, On.
    Posts
    1,127
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok.

    I read through the wiki page, and there are some good points against the use of globals.


    However...

    Quote Originally Posted by wiki
    # Non-locality -- Source code is easiest to understand when the scope of its individual elements are limited. Global variables can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.
    Agreed. But we're not talking about an army of global variables. One $db global is fairly self-evident as to what it does, and is easy to spot inside code when used.

    Quote Originally Posted by wiki
    # No Access Control or Constraint Checking -- A global variable can be get or set by any part of the program, and any rules regarding its use can be easily broken or forgotten. (In other words, get/set accessors are generally preferable over direct data access, and this is even more so for global data.)
    Shouldn't be an issue with a database connection.

    We'll only be using it to run queries, after all.

    Quote Originally Posted by wiki
    # Implicit coupling -- A program with many global variables often has tight couplings between some of those variables, and couplings between variables and functions. Grouping coupled items into cohesive units usually leads to better programs.
    Again, not an issue.

    Quote Originally Posted by wiki
    # Concurrency issues -- if globals can be accessed by multiple threads of execution, synchronization is necessary (and too-often neglected).
    Not an issue in PHP.

    Quote Originally Posted by wiki
    # Namespace pollution -- Global names are available everywhere. You may unknowingly end up using a global when you think you are using a local (by misspelling or forgetting to declare the local) or vice versa. Also, if you ever have to link together modules that have the same global variable names, if you are lucky, you will get linking errors. If you are unlucky, the linker will simply treat all uses of the same name as the same object.
    A global $db variable or one $db per namespace, makes no difference.

    Quote Originally Posted by wiki
    # Memory allocation issues -- Some environments have memory allocation schemes that make allocation of globals tricky. Also, when dynamically linking modules, it can be unclear whether different libraries have their own instances of globals or whether the globals are shared.
    Not a PHP issue.


    So, while I agree there is no need to have many global variables, and in fact it should be avoided, the argument is very weak against having ONE global variable that holds a resource pointer to the database connection.


    I'm not trying to argue here.

    I'm genuinely interested in why things that are perfectly legal and useable in PHP are villified simply because they create problems in other languages.

  17. #17
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Viflux
    To expand on that...

    The language provides you, the programmer, the ability to make use of a global variable. And yet, it has become like witchcraft.

    I don't understand.

    Is there some advanced PHP techniques which require you not use global objects?
    OOP and global variables are a bad mix, and here's why: Objects should be black boxes, in the sense that the public interface is the only thing you need to know to use them. How the object implements its functionality is completely hidden, and should be considered subject to change at any moment. This is called information hiding (or sometimes encapsulation) and is one of the main benefits of OOP. Using global variables that are accessed from within objects breaks this information hiding by giving you a means of modifying the operation of the object in realtime without having to use its interface. It also means that the implementation of the object depends on something outside the object, making it less self contained. Again, one of the main tenets of OOP is that information should only flow to and from the object from a well defined interface.

    The use of singletons for things like sharing connections is not ideal, but is much better than global variables because they're read-only and are guaranteed to return a certain type of object.

    Now, you could say it's just ONE global variable, it doesn't make much of a difference, but it comes down to this; when you or someone else is going to look at that object to use it again in a year from now, you won't be able to just by looking at the interface, you'll HAVE to look at the implementation to see what global variables were used, a situation easily avoided by simply passing a reference to the database in the constructor.

    Most languages allow you to do many things that are considered bad practice; just because you can doesn't mean you should!

  18. #18
    Employed Again Viflux's Avatar
    Join Date
    May 2003
    Location
    London, On.
    Posts
    1,127
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I totally agree with you.

    But unless I'm completely missing the boat, the contention here is that this

    PHP Code:
    $db databaseconnection;

    $thing = new Thing$db ); 
    is bad?

    That's using a global variable and following your suggestion. Or am I missing something here.

  19. #19
    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 Viflux
    I totally agree with you.

    Or am I missing something here.
    You are.

    This is bad :
    PHP Code:
    class Thing
    {
        function 
    foo() {
            global 
    $db;
            
    $db->query();
        }
    }
    $db databaseconnection;
    $thing = new Thing();
    $thing->foo(); 
    What you demonstrated is passing the connection on, witch is probably the best solution overall. (Even preferred over Singleton)

  20. #20
    Employed Again Viflux's Avatar
    Join Date
    May 2003
    Location
    London, On.
    Posts
    1,127
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I see.

    So I've been frustrated for nothing.

    The terminology here had me baffled. I've always refered to a variable declared outside of functions/methods/classes to be global...

  21. #21
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by duuudie

    I would like all my classes to have the ability to execute bits of code like this:
    PHP Code:
    $result $db->query($sql); 
    without having to worry about where $db comes from, where it has been instantiated, if it must be passed to a composed objects or what not.

    What do you think about it?
    $result = db_query($sql);

    or, for oop fans among us

    $result = DB::query($sql);

    php is a simple language and desinged to keep things simple.

  22. #22
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Viflux
    The terminology here had me baffled. I've always refered to a variable declared outside of functions/methods/classes to be global...
    And so it is. The issue is not about having global variables, but about using them.

    In your example, when the function is passed a global variable as a parameter, it actually doesn't use the global -- a separate variable, which has its name defined in the function definition and which exists only in the scope of the function, is created.

    Don't confuse variables with their contents. In PHP, actually, no variable has a truly global scope, meaning that it is accessible from inside functions. With the global keyword you actually create a new variable of the same name as the global one, but holding the reference to the contents of the global one. IOW, this
    PHP Code:

    function some_function()
    {
        global 
    $global_var;
        
    // some useful code
    }

    $global_var 'something';
    some_function(); 
    is effectively no different from
    PHP Code:
    function some_function(&$global_var)
    {
        
    // some useful code
    }

    $global_var 'something';
    some_function($global_var); 
    The only difference is that with the latter example we know what is coming into the function from the outside, which leaves the actual implementation nicely encapsulated.

  23. #23
    SitePoint Enthusiast
    Join Date
    Feb 2004
    Location
    Montreal
    Posts
    77
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The biggest benefit to the singleton pattern that I see is the localization of instanciation. Ok, what I mean is that the database can only be opened through one bit of code. This is good because in very complex systems, there is the possibility of querying a global database object that has not yet been created. The singleton pattern guarantees instanciation and that the object will only be created once. If the application is simple and the execution path is fairly strightforward, then a global database object might not be such a bad things. In either event, the singleton pattern doesn't add that much typing but provides benefits over using a global variable. Hope this helps.

  24. #24
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by Viflux
    Agreed. But we're not talking about an army of global variables. One $db global is fairly self-evident as to what it does, and is easy to spot inside code when used.
    Each global is another thing you have to be aware of. More than about five things in your head at once, and you drop the lot. Without the global you can manage 25% more complexity. It's like saying you only lose 5 IQ points and so won't notice. Well, you probably will notice and you will certainly care when you get the second global.

    Consider importing another library. What do you think their global database connection will be called?

    Quote Originally Posted by Viflux
    Shouldn't be an issue with a database connection.
    It's even more of an issue with a DB connection. That connection has to be opened and closed. How is another part of your code going to know that the connection is open when it uses it? How does it know that it is tasked with closing it? It could even be null when you get it. Do you handle the connection or pass an error? If you open the connection, how do you know the username and password taht the other part of your program uses? What happens when you need two connections?

    With a global yo simply cannot guarantee the state it will be in when you use it. At least with a Singleton you know it will have been set up.

    Quote Originally Posted by Viflux
    We'll only be using it to run queries, after all.
    As SQL is usually a fully fledged programming language, I don't see this as much of a restrction .

    Quote Originally Posted by Viflux
    Again, not an issue.
    Always an issue and a really serious one with an infrastructure component like a DB connection.

    Suppose you move part of your system on to a separate database, say the read only data for load balancing. Suddenly you are going to have to have two globals and you are going to have to change by hand a heck of a lot of code. Code that cannot be used in any other project, by the way. I hope you like writing the same code over and over.

    Quote Originally Posted by Viflux
    Not an issue in PHP.
    I nearly coughed my dinner straight into my monitor on this one. A web server has many, many simultaneous requests. Please, please don't tell me you build database driven web sites without using transactions.

    If the connection is global, who begins the transaction? Who commits it? These are synchonisation issues. Issues that you drive a horse and cart through by using a global.

    Quote Originally Posted by Viflux
    A global $db variable or one $db per namespace, makes no difference.
    It makes every difference if you are ever going to write more than a few hundred lines of code. Programming a meaningful project is hard. So hard that we use divide and conquer by breaking up the software into modules. A global ties modules together by an invisible chord. Not only have we failed to modularise, we don't even know that we have failed to modularise. Great fun for the poor programmer who has to pick up this mess when you move on.

    Quote Originally Posted by Viflux
    Not a PHP issue.
    In as much as it was language specific, no. In PHP it is only global for one request. However, poluting the session namespace has the same issues with register_globals turned on. Things are always more complicated than they first seem.

    Quote Originally Posted by Viflux
    So, while I agree there is no need to have many global variables, and in fact it should be avoided, the argument is very weak against having ONE global variable that holds a resource pointer to the database connection.
    If I am running a marathon, I don't want to be carrying a brick in my pocket. not even one. Also taht first global will cause a lot of harm. The second I see it, I won't know that it is the only one. It won't worry me after thet though. The whole lot will have been deleted. Developer time is way to expensive to waste tracking down elementary bugs caused by dangerous code.

    Quote Originally Posted by Viflux
    I'm genuinely interested in why things that are perfectly legal and useable in PHP are villified simply because they create problems in other languages.
    They create problems in all languages where you are writing more than a few dozen lines of code, or where you cannot keep the whole thing in your head, or where two programmers may be involved or just about any other factor coming in from the real world.

    It's hacking, and has no place in code that people have paid money for.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  25. #25
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Viflux
    I see.

    So I've been frustrated for nothing.

    The terminology here had me baffled. I've always refered to a variable declared outside of functions/methods/classes to be global...
    The problem probably stems from the PHP documentation; they use the word 'global' to describe the context of the variable, rather than the scope. For variables with global scope, they use the term 'superglobal'. This is unfortunately inconsistent with (pretty much) every other languages out there.

    The thing to keep in mind, then, is that it's the 'global' keyword which shouldn't be used.


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
  •