6

I'm currently creating blog system, which I hope to turn into a full CMS in the future.

There are two classes/objects that would be useful to have global access to (the mysqli database connection and a custom class which checks whether a user is logged in).

I am looking for a way to do this without using global objects, and if possible, not passing the objects to each function every time they are called.

Nico Burns
  • 16,639
  • 10
  • 40
  • 54

4 Answers4

13

You could make the objects Static, then you have access to them anywhere. Example:

myClass::myFunction();

That will work anywhere in the script. You might want to read up on static classes however, and possibly using a Singleton class to create a regular class inside of a static object that can be used anywhere.

Expanded

I think what you are trying to do is very similar to what I do with my DB class.

class myClass
{
    static $class = false;
    static function get_connection()
    {
        if(self::$class == false)
        {
            self::$class = new myClass;
        }
        return self::$class;
    }
    // Then create regular class functions.
}

What happens is after you get the connection, using $object = myClass::get_connection(), you will be able to do anything function regularly.

$object = myClass::get_connection();
$object->runClass();

Expanded

Once you do that static declarations, you just have to call get_connection and assign the return value to a variable. Then the rest of the functions can have the same behavior as a class you called with $class = new myClass (because that is what we did). All you are doing is storing the class variable inside a static class.

class myClass
{
    static $class = false;
    static function get_connection()
    {
        if(self::$class == false)
        {
            self::$class = new myClass;
        }
        return self::$class;
    }
    // Then create regular class functions.
    public function is_logged_in()
    {
        // This will work
        $this->test = "Hi";
        echo $this->test;
    }
}

$object = myClass::get_connection();
$object->is_logged_in();
Tyler Carter
  • 60,743
  • 20
  • 130
  • 150
  • Hi, thanks for your answer, is it possible to save variables in static classes. i.e. call function to check whether user is logged in, and then access this variable several times later in the page? – Nico Burns Jul 18 '09 at 17:35
  • 2
    Yes, for a static class do the same thing I did to declare the variable $class. The only thing is that you 'have' to declare every variable you use. – Tyler Carter Jul 18 '09 at 17:36
  • 1
    But, the code I gave you allows you to use any regular class, well, regularly. The static part simply gives you the class, instead of globaling it. I'll edit to show a little more. – Tyler Carter Jul 18 '09 at 17:38
  • wow. thanks a lot, I would press the up arrow twice if I could. Am I right in thinking that the get_connection() function retrieves the previous created object? (or creates the object if its hasn't already been created) – Nico Burns Jul 18 '09 at 17:46
  • 1
    Exactly! The entire Static class is simply a container for the created class. – Tyler Carter Jul 18 '09 at 17:48
  • 4
    A static class is just another type of global object. – troelskn Jul 18 '09 at 17:57
  • 1
    Aha! I have the idea now. One more question, the "public" bit of "public function is_logged_in()", is that specific to a static class, or is that just how you declare all of your functions? – Nico Burns Jul 18 '09 at 18:01
  • The public part is simply something I put in by default. It has to do with PHP5 and visibility. Public means anyone, in or outside of the class can see it. Protected and Private are other visibility settings. – Tyler Carter Jul 18 '09 at 18:16
  • 1
    -1, classes are global symbols too, so static public members of classes qualify as global variables. It's just the syntax that is different. – Ionuț G. Stan Jul 18 '09 at 19:34
  • 2
    You don't have to global it everytime that you create a new file or class, which was the base problem the OP was trying to fix. – Tyler Carter Jul 18 '09 at 19:37
  • What would happen if the same logic is implemented in the constructor for the class? Just curious. – Gokul N K Apr 14 '14 at 13:19
  • There is an error in your code. When $class is false you create a new instance of it, yet you don't return it. This throws an error because $object is then passed a null reference. It should be: if(self::$class == false) { self::$class = new myClass; } return self::$class; – Porlune Jul 11 '15 at 15:52
  • @Porlune I completely agree. This was written so long ago. Thanks for pointing that out. – Tyler Carter Jul 14 '15 at 13:18
8

You could pass the currently global objects into the constructor.

<?php
  class Foo {
    protected $m_db;
    function __construct($a_db) {
      $this->m_db = $a_db;
    }
  }
?>
troelskn
  • 115,121
  • 27
  • 131
  • 155
Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
3

I recently revamped my framework in preparation for the second version of our company's CMS. I undid a huge amount of the things I made static in order to replace them with normal objects. In so doing, I created a huge amount of flexibility that used to rely on me going through and hacking into core files. I now only use static constructs when the only alternative is global functions, which is only related to low-level core functionality.

I'm going to show a few lines of my bootstrap.php file (all of my requests get sent through that file, but you can achieve the same result by including it at the top of every file) to show you what I mean. This is an pretty hefty version of what you'd probably use in your situation, but hopefully the idea is helpful. (This is all slightly modified.)

 //bootstrap.php

...

// CONSTRUCT APPLICATION

{       
    $Database = new Databases\Mysql(
        Constant::get('DATABASE_HOST'),
        Constant::get('DATABASE_USER'),
        Constant::get('DATABASE_PASSWORD'),
        Constant::get('DATABASE_SCHEMA')
    );

    $Registry     = new Collections\Registry;
    $Loader       = new Loaders\Base;
    $Debugger     = new Debuggers\Dummy; // Debuggers\Console to log debugging info to JavaScript console

    $Application  = new Applications\Base($Database, $Registry, $Loader, $Debugger);
}

...

As you can see, I have all kind of options for creating my application object, which I can provided as an argument in the constructor to other objects to give them access to these "global" necessities.

The database object is self-explanatory. The registry object acts as a container for object I may want to access elsewhere in the application. The loader acts as a utility for loading other resources like template files. And the debugger is there to handle debug output.

I can, for example, change the database class that I instantiate and, voila I have a connection to a SQLite database. I can change the class of the debugger (as noted) and now all of my debug info will be logged to my JavaScript console.

Okay, now back to the issue. How do you give other objects access to all of this? You simply pass it in an argument to the constructor.

// still bootstrap.php

...

// DISPATCH APPLICATION

{
    $Router = new Routers\Http($Application);
    $Router->routeUri($_SERVER['REQUEST_URI']); 
}

...

Not only that, but my Router (or whatever object I construct with it) is more flexible, too. Now I can just instantiate my application object differently, and my Router will behave differently accordingly.

Ryan Williams
  • 959
  • 7
  • 15
1

Well, if you already have some object by which you refer to the blog system, you can compose these objects into that, so that they're $blog->db() and $blog->auth() or whatever.

chaos
  • 122,029
  • 33
  • 303
  • 309