4

I have a class userdb in which I am declaring a function that returns the connection to the database:

return $con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);

I have various functions, even across other classes, where I have to access $con (e.g. to pass a query or to fetch data), but I can't access this variable.

Is there a better way to define and use a database class? Remember that I have other classes where I need to access the userdb class.

Ryan Kohn
  • 13,079
  • 14
  • 56
  • 81
Kazim King
  • 67
  • 1
  • 10

7 Answers7

3

I would advise you to use the Singleton Pattern for this:

In your userdb class, declare a static property $scon:

private static $scon;

and assuming the function you mention above is named createConnection(), you should create the folowing static method:

public static function connect() {
    if (empty(self::$scon)) {
         $instance = new userdb();
         self::$scon = $indtance->createConnection(); 
    }
    return self::$scon; 
}

With this, you will be able to access your userdb connection with:

userdb::connect();

Also since this is a singleton, it will only connect once, and use that connection until the end of the script.

Note (on dependency injection): Since @KevinM1 mentioned Dependency Injection, I must add that it is also a possible, and far superior solution. It requires you to create a setConnection() method (or an Abstract ancestor) for all your classes using a database connection, and during the instatiation of these classes you may use a Factory to add the required connection to the object. This should be wrapped inside some class loader, which is avare of your model structure.

See, peace of cake, but for small and fast developement I would stick with the Singleton ;)

aorcsik
  • 15,271
  • 5
  • 39
  • 49
  • Dependency injection is a far superior solution. – Major Productions Oct 19 '12 at 12:00
  • 2
    @KevinM1: Ofc, but for smaller projects this is a very well suited solution. I would also add some Lazy Loading too, but that was not the question here. – aorcsik Oct 19 '12 at 12:01
  • Perhaps. I think it's easier to just take advantage of the default pass-by-reference behavior during the bootstrap stage. Generally speaking, you know when you're going to need to access a db up front. For smaller projects, instead of going through the hoops of an actual DI container, just instantiate the db object and manually pass it to the other objects that need it. You get the same single instance, but without the temptation to blow apart scope. – Major Productions Oct 19 '12 at 12:05
  • My problem with singleton, beyond the scope/encapsulation issues, is that it acts like a normal 'global' in terms of use. Code that uses a singleton cannot mention/refer to that use in its method signatures. That implicit requirement = tighter coupling, which is the antithesis of OO. – Major Productions Oct 19 '12 at 12:09
  • I absolutely agree with you, and I use DI in my projects too, but the asker is new to PHP, and maybe he would end up using `global $con` for its simplicity To prevent that, and for staying in _OOP land_, introducing Singleton makes is a good choice here. – aorcsik Oct 19 '12 at 12:19
1

If it's in a class, store the instance in a property:

class userDB
{

   public $dbCon = false;//because you want to access the instance 
   //from outside the class, I have made the property public

    function connect()
   {

      $con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);

      $this->dbCon = $con;

   }


}

TO access it outside of the class:

$useDBInstance->dbCon;

0
return $this->con 

return this way from your class and call it this way..

$this->classObject->con->prepare();
Man Programmer
  • 5,300
  • 2
  • 21
  • 21
0

Well, $con will already be an object, as it's instantiating a new PDO object. Unless you're trying to add functionality to your PDO object, wrapping it is pointless.

That said, the best way to share your userdb/PDO object (depending on whether or not you stick with the wrapper) with other objects is to use Dependency Injection. That's a fancy term for passing your db to whatever object needs it. Since objects are defaultly passed by reference in PHP, if you create your db object first, all objects that receive it as a constructor/method argument will be using that same single instance.

EDIT: Link to Dependency Injection implementation

EDIT2: Clarification on DI in small projects -

The normal DI pattern generally requires a special object called a DI Container. This is a special use object that automatically injects the dependency into the object that needs it. For small projects, it's overkill. The simple, low complexity version of DI is simply:

class SomeClass {
    protected $db;

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

class SomeClass2 {
    public function SomeMethod($db) {
        // do something with the db
    }
}

$db = new PDO(/* connection string */);

$obj = new SomeClass($db, /* other constructor args */);

// or

$obj2 = new SomeClass2(/* constructor args */);
$obj2->someMethod($db, /* method args */);

The magic is that since objects are passed by reference by default in PHP, $obj and $obj2 are using the same db connection.

The whole idea is to not blow apart scope or encapsulation by having a static method, and to ensure that classes and their methods are up front about what they require in order to work.

Singletons do the exact opposite. They're accessed through static methods, which bypass scope, and since they're invoked and not passed, they never show up in method signatures, so anyone not familiar with the code won't be aware of that hidden requirement. Even Erich Gamma, one of the people who helped codify the Singleton Pattern has regrets about it:

I'm in favor of dropping Singleton. Its use is almost always a design smell.

In PHP, where there's no concept of shared memory, and where scripts execute once per request, the only reason to want to use a singleton is to have easy access to a single resource. Since objects are passed by reference, a single instance can be shared with multiple objects naturally. From there, it's about good design and delegation.

Community
  • 1
  • 1
Major Productions
  • 5,914
  • 13
  • 70
  • 149
0

Checkout my video tutorial + code for an alternative to global PHP variables.

You're doing it wrong there. You need to use a static variable if you plan to create your connection in a function and store it there. Otherwise you'll keep connecting on every function call. My tutorial explains this very concept of static variables within regular functions.

If it's not clear enough, let me know and I'll try to answer your questions.

Here's some code to accompany this:

/**
* Arguments are none or [$db, [$user, [$pass[, $host]]]].
*
* @return PDO
*/
function PdoDb(){
    static $con = null; // I'm explicit :)
    // Every time you pass Arguments you reconnect
    if(func_num_args()){
        $args = array_pad(func_get_args(), 4, null);
        list($db, $user, $pass, $host) = $args;
        if(empty($user)) $user = 'root';
        if(empty($host)) $host = 'localhost';
        $con = new PDO("mysql:host={$host};dbname={$db}", $user, $pass);
    }
    if(empty($con)){
        trigger_error('Provide arguments to connect first.', E_USER_ERROR);
        return null;
    }
    return $con;
}

// First run (provide arguments to connect)
PdoDb($db, $user, $pass, $host);
PdoDb($db); // Works if you connect root@localhost with no password

// From here on (it returns PDO)
PdoDb()->DoStuffOfPdo();

Once connected it stays that way. But you can reconnect at will to by providing arguments.

CodeAngry
  • 12,760
  • 3
  • 50
  • 57
-2

use singlton class implimentation

class connectdb
{
    protected static $_instance = NULL;


    private function __construct()
    {
    }

    public function getinstance()
    {
     if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
    public function connect()
    {
     $this->connection =new PDO("mysql:host=$host;dbname=$db", $user, $pass);


    }

}
Arun Killu
  • 13,581
  • 5
  • 34
  • 61
  • There's no reason to ever use a singleton in PHP given it's fire-and-forget nature. Dependency injection is the way to go. – Major Productions Oct 19 '12 at 11:59
  • IMO, yes. Others will disagree. – Major Productions Oct 19 '12 at 12:17
  • 1
    This isn't "wrong". It's just not the **best** way of doing it. And even then, some people would say otherwise (which is perfectly fine). The downvote on this is completely unnecessary. +1 –  Oct 19 '12 at 12:35
-4

for using a variable within a class function or independent function you need to place a global keyword

$conn=mysql_connect(); 
   function test(){
      global $conn;
   }

now $conn will be available within the scope of test function, and it will be available everywhere when defined at the top of the script. For class also you need to do the same thing, make a object of a class and declare it as global within a function

Andro Selva
  • 53,910
  • 52
  • 193
  • 240
  • `global $x;` is a thing of the past. It is completely unnecessary to use it in a case like this. –  Oct 19 '12 at 11:57
  • 1
    'global' is NOT the way to go, ever, in PHP. Especially in an OO context where scope and encapsulation are paramount. There are far better alternatives. – Major Productions Oct 19 '12 at 11:57