4

A couple of the options are:

$connection = {my db connection/object};

function PassedIn($connection) { ... }

function PassedByReference(&$connection) { ... }

function UsingGlobal() {
    global $connection;
    ...
}

So, passed in, passed by reference, or using global. I'm thinking in functions that are only used within 1 project that will only have 1 database connection. If there are multiple connections, the definitely passed in or passed by reference.

I'm thining passed by reference is not needed when you are in PHP5 using an object, so then passed in or using global are the 2 possibilities.

The reason I'm asking is because I'm getting tired of always putting in $connection into my function parameters.

Darryl Hein
  • 142,451
  • 95
  • 218
  • 261
  • See http://stackoverflow.com/questions/1967548/best-way-to-access-global-objects-like-database-or-log-from-classes-and-scripts for a more broad discussion of this topic. – philfreo Dec 28 '09 at 00:42

6 Answers6

4

I use a Singleton ResourceManager class to handle stuff like DB connections and config settings through a whole app:

class ResourceManager {
    private static $DB;
    private static $Config;

    public static function get($resource, $options = false) {
        if (property_exists('ResourceManager', $resource)) {
            if (empty(self::$$resource)) {
                self::_init_resource($resource, $options);
            }
            if (!empty(self::$$resource)) {
                return self::$$resource;
            }
        }
        return null;
    }

    private static function _init_resource($resource, $options = null) {
        if ($resource == 'DB') {
            $dsn = 'mysql:host=localhost';
            $username = 'my_username';
            $password = 'p4ssw0rd';
            try {
                self::$DB = new PDO($dsn, $username, $password);
            } catch (PDOException $e) {
                echo 'Connection failed: ' . $e->getMessage();
            }
        } elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
            self::$$resource = new $resource($options);
        }
    }
}

And then in functions / objects / where ever:

function doDBThingy() {
    $db = ResourceManager::get('DB');
    if ($db) {
        $stmt = $db->prepare('SELECT * FROM `table`');
        etc...
    }
}

I use it to store messages, error messages and warnings, as well as global variables. There's an interesting question here on when to actually use this type of class.

Community
  • 1
  • 1
Jrgns
  • 24,699
  • 18
  • 71
  • 77
  • Nice, I like that idea. Now I'll have to see how I can implement it. – Darryl Hein Oct 23 '08 at 06:56
  • I started using it not too long ago, and it opened up a lot of possibilities for me. It's MUCH better than messy global variables and db parameters to each function. It also keeps the global namespace clean of variables. – Jrgns Oct 23 '08 at 07:45
  • This is just as global as a global variable. Static is NOT a solution to avoid global state, constructor injection is. – markus Dec 29 '12 at 23:08
2

Try designing your code in an object-oriented fashion. Methods that use the database should be grouped in a class, and the class instance should contain the database connection as a class variable. That way the database connection is available to the functions that need it, but it's not global.

class MyClass {
  protected $_db;

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

  public function doSomething()
  {
    $this->_db->query(...);
  }
}
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • The main issue here is that it is quite annoying to have to pass a $db object into classes which are frequently instantiated. And what if there are static functions that also need the $db object? Should you have to pass $db into those as well? It certainly works, but seems unnecessary. – philfreo Dec 28 '09 at 00:02
  • No, it's not unnecessary, constructor injection is the only clean way of developing testable, decoupled code. – markus Dec 29 '12 at 23:09
2

I see that a lot of people have suggested some kind of static variable.

Essentially, there is very little difference between a global variable and a static variable. Except for the syntax, they have exactly the same characteristics. As such, you are gaining nothing at all, by replacing a global variable with a static variable. In most examples, there is a level of decoupling in that the static variable isn't referred directly, but rather through a static method (Eg. a singleton or static registry). While slightly better, this still has the problems of a global scope. If you ever need to use more than one database connection in your application, you're screwed. If you ever want to know which parts of your code has side-effects, you need to manually inspect the implementation. That's not stuff that will make or break your application, but it will make it harder to maintain.

I propose that you chose between one of:

  • Pass the instance as arguments to the functions that needs it. This is by far the simplest, and it has all the benefits of narrow scope, but it can get rather unwieldy. It is also a source for introducing dependencies, since some parts of your code may end up becoming a middleman. If that happens, go on to ..

  • Put the instance in the scope of the object, which has the method that needs it. Eg. if the method Foo->doStuff() needs a database connection, pass it in Foo's constructor and set it as a protected instance variable on Foo. You can still end up with some of the problems of passing in the method, but it's generally less of a problem with unwieldy constructors, than with methods. If your application gets big enough, you can use a dependency injection container to automate this.

troelskn
  • 115,121
  • 27
  • 131
  • 155
1

My advice is to avoid global in the bulk of the code - it's dangerous, hard to track and will bite you.

The way that I'd do this is to have a function called getDB() which can either be at class level by way of a constructor injection or static within a common class.

So the code becomes

class SomeClass {
    protected $dbc;

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

    public function getDB() {
        return $this->dbc;
    }

    function read_something() {
        $db = getDB();
        $db->query();
    }
}

or using a common shared class.

function read_something() {
    $db = System::getDB();
    $db->query();
}

No matter how much elegant system design you do, there are always a few items that are necessarily global in scope (such as DB, Session, Config), and I prefer to keep these as static methods in my System class.

Having each class require a connection via the constructor is the best way of doing this, by best I mean most reliable and isolated.

However be aware that using a common shared class to do this can impact on the ability to isolate fully the objects using it and also the ability to perform unit tests on these objects.

Manoj Sharma
  • 1,467
  • 2
  • 13
  • 20
Richard Harrison
  • 19,247
  • 4
  • 40
  • 67
  • Your advice to void global is good but your solutions are both a form of global state. – markus Dec 29 '12 at 23:07
  • thanks - looking back at this answer I realise that it wasn't clear that I was proposing either constructor injection or singleton and that I hadn't explained properly the benefits and drawbacks of each approach. answer now edited. – Richard Harrison Jan 03 '13 at 08:10
0

None of the above.

All the mysql functions take the database connection argument optionally. If you leave that argument out, the last connection by mysql_connect() is assumed.

Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
-1
function usingFunc() {
  $connection = getConnection();
  ...
}

function getConnection() {
  static $connectionObject = null;
  if ($connectionObject == null) {
    $connectionObject = connectFoo("whatever","connection","method","you","choose");
  }
  return $connectionObject;
}

This way, the static $connectionObject is preserved between getConnection calls.

Piskvor left the building
  • 91,498
  • 46
  • 177
  • 222