tags:

views:

310

answers:

4

Its difficult to explain this situation but please see the example.

I have coded a website where the page loads, I initialize a database class. I sent this class as a function parameter to any functions that needs to access database.

I know this is bad approach but currently I have no clue how to do this any other way. Can you please help me.

Example

class sms {

    function log_sms($message, $db) {

     $sql = "INSERT INTO `smslog` SET
      `mesasge` = '$message'
      ";
     $db->query($sql);

     if ($db->result)
      return true;
     return false;
    }

}

then on the main page..

$db = new db(username,pass,localhost,dbname);

$sms = new sms;

$sms->log_sms($message, $db);

Is there any better approach than this ?

+2  A: 

For starters you can make a protected $db variable in each of your classes that need to utilize the database. You could then pass $db in to the class constructor. Here's the updated code:

$db = new db(username,pass,localhost,dbname);
$sms = new sms($db);
$sms->log_sms($message);

class sms {

    protected $db;

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

    public function log_sms($message) {
        $sql = "INSERT INTO `smslog` SET
                `mesasge` = '$message'
                ";
        $this->db->query($sql);

        if ($this->db->result)
                return true;
        return false;
    }
}

This example is in PHP 5.

cballou
is this the best way? I have almost 14 classes, so shall I add a constructor to each one of them ?P.S This is for a social networking website
atif089
There is no best way. The approach cballou gives certainly is a good way. In order to know whether it is a good way for your 14 classes we would need to know what they are. In any case, if you have methods on those 14 classes like log($msg, $db) you would need to pass the $db object as many times (probably even more) than you would have to when passing it in as a constructor argument.
koen
Yes by 14 classes I mean that I have 14 more classes that need the use of DB class (like profile, usersettings, albums, videos, auth, messages, networks, referrals, updates etc) and yes I provide db in each of the method's arguments.I use $db as and argument for about 50 or more such methods I believe. I don't mind changing the complete code if there is a better way, because there are lot more things to be added to the website.
atif089
This will reduce passing $db as an argument from 50 to 14 if that's any indication of improvement. @stereo's solution is the way to go for those who understand proper OOP and patterns. It would be the most maintainable in the future if you have to go back in and add new database abstraction layers (i.e. caching, another db, etc).
cballou
A: 

You could either have a static class that has two lists, one of available connections, the other of handed out connections, and just have a connection pool.

Or, if you are using something that has a quick connection time, such as MySQL, then just create the connection in your database class, do all the queries needed for that functionality, then close it. This is my preferred approach.

James Black
Im using only 1 connection in order to save resources as the website is on a shared server lol
atif089
Then why not just queue up the queries, process them, and pass the results in a callback, packaged, otherwise you will run into problems when two threads try to use the same connection.
James Black
I cant, because I wrote a class for each of the function, like one class to authenticate user, one to get the users details, one to read users inbox and so and, and they use the main $db class. which initializes on top of the index file and the methods are processed one after the otherEach method has the query to pull out only the required things and return an array. The HTML is rendered on template page like MVC. So second query is executed only after the first one.However I hate adding $db on every function and I have a perception if it makes things slow
atif089
You should add these statements to your question, it would help ensure you get the best possible answer.
James Black
+6  A: 

there are number of options how to resolve dependencies problem (object A requires object B):

constructor injection

  class Sms { 
        function __construct($db) ....
  }

  $sms = new Sms (new MyDbClass);

setter injection

  class Sms { 
        protected $db;
  }
  $sms = new Sms;
  $sms->db = new MyDbClass;

'registry' pattern

 class Registry {
     static function get_db() {
          return new MyDbClass;
 }}

 class Sms {
      function doSomething() {
          $db = Registry::get_db();
          $db->....
  }}

'service locator' pattern

 class Loader {
     function get_db() {
          return new MyDbClass;
 }}

 class Sms {
      function __construct($loader) {
         $this->loader = $loader;

      function doSomething() {
          $db = $this->loader->get_db();
          $db->....
  }}

  $sms = new Sms(new Loader);

automated container-based dependency injection, see for example http://www.sitepoint.com/blogs/2009/05/11/bucket-is-a-minimal-dependency-injection-container-for-php

   interface DataSource {...}
   class MyDb implements DataSource {...}

    class Sms {
        function __construct(DataSource $ds) ....


    $di = new Dependecy_Container;
    $di->register('DataSource', 'MyDb');
    $sms = $di->get('Sms');

to name a few ;)

also the Fowler's article i gave you before is really worth reading

stereofrog
do you have a clue of processing times of each ? which is faster and which is slower? Or if there is not much difference then constructor thing looks simplest for me :)
atif089
Ooh, nice overview. Thanks :)
Svish
@atif089: proper thinking is much more important than processing speed. You can get a new CPU for a bunch of dollars, but no money in the world can make you smarter ;)
stereofrog
You and I understand the `Registry` and `ServiceLocator` patterns differently. To me, your Registry looks like a ServiceLocator (a Registry that knows how to instantiate objects) and your ServiceLocator looks like well... a ServiceLocator that's implemented into another class via composition. And nothing here looks like a Registry.
Peter Bailey
@stereofrog lol very true, the constructor injection method seems simple for me to implement and @Nazariy 's singleton method seems efficient. Which one would you suggest?This is for a social networking website with atleast 200 active users and at times upto 2-5k. So optimization is really the backbone.
atif089
my personal favourite is the ServiceLocator ("loader"), constructor injection can be messy if you need several "global" objects (think Request, Response, Db, Session etc). Regarding optimization i'd suggest that you design an application in a proper way first and then search for the real bottlenecks. Most probably this will be db and IO stuff and not php object wiring.
stereofrog
+1  A: 

Singleton is also good practice in application design. They are very useful to avoid repeated queries or calculations during one call. Passing Database object to every method or constructor is not a very good idea, use Singleton instead.

extend your database, or insert static method inside your db class. (I would also call for config within db constructor method)

class database extends db
{
 public static function instance()
 {
  static $object;

  if(!isset($object))
  {
   global $config;

   $object = new db($config['username'],$config['pass'],$config['localhost'],['dbname']);
  }

  return $object;
 }
}

make your method static

class sms {

    public static function log($message) {

        $sql = "INSERT INTO `smslog` SET `mesasge` = '$message'";

        database::instance()->query($sql);

  return (bool) database::instance()->result;
    }
}

Next time you need to log sms just do static call like this

sms::log($message);
Nazariy