Thread: DB class
nutballs

I know someone (td i think) just suggested we work a bit on getting a good DB class going, but im an impatient bastard and I am still busy trying to make my framework. So....

can someone help me to refine this class that I am trying to wrap my baby-fished brain around...
This is a very simplified class, only opening the database connection. I just need to make sure I am heading in the right direction.


class database
{
public $conn;

function __construct() {
      $GLOBALS['database'] = &$this;
      opendb('server','database','username','password');
  }

public function opendb($server,$database,$username,$password)
{
    $db = mysql_connect( $server, $username, $password,true) or die('Could not connect to database server.' );
    mysql_select_db($database, $db) or die('Could not select database.');
    $this->conn = $db;
}

}

the result in theory would be an ability to access the connection from any other class, via the $globals array. make sense? so what am i doing that is fataly wrong, if i am doing such a thing? it physically works though.

vsloathe

Looks good to me. I try not to use any

PHP

 5 specific stuff so that my code will work on shared hosting, but it looks like you don't care about that.

perkiset

Couple thoughts NB -

although putting the global reference to the object in the constructor looks interesting, this makes the class a singleton (or at least it should be) because if you accidentally create it twice, you'll overwrite the handle of the first one. The simplest fix here would be:


<?

php

 

__construct()
{
if ($GLOBALS['database'])
throw new Exception('Recreating the database object! Bad Nutballs! Bad Nutballs!');

// now proceed on as you had...
}
?>



But that being said, I'm just not a fan of doing that because it locks me into a single usage of that class. I do something very similar, but in my primary code instead so that I can create more DB instances if I wish. For example:

$db = new dbConnection('127.0.0.1', 'username', 'password', 'database');
$GLOBALS['utilDB'] = &$db;

I often have multiple database connections open (think master detail) and maintain a single "utility" database system wide but then create others as I need them.

Note also that I put the connection parameters right into the constructor - this is because I wanted to infer that a db connection is bound to ... erm ... it's connection. If I need to do something as weird as connect to two different <i>databases</i> then I create two different connections rather than re-using, because the code is harder for me to read. However, those params on the constructor do not force an "open" of the db yet... there is a flag set in the constructor that says "connected = false" and the actuary methods (query, singleAnswer etc) first check to see if the object is connected before executing. This makes it so that I can include a DB object every page pull with almost no overhead - regardless of if I use it or not - because it won't actually connect until it is needed.

<edit>I forgot - my base class for dbConnect is in the

php

  repository... perhaps that's what you're thinking of, unless that one is really inadequate - in which case, I'd really love to know it so I can grow it</edit>

m0nkeymafia

I believe we should set a standard of making errors talk about yourself in the third person.

i.e.
"m0nkeymafia is displeased at your lack of skill"

perkiset

That's SO kaptain of you Applause

m0nkeymafia

quote author=perkiset link=topic=730.msg5108#msg5108 date=1201261674

That's SO kaptain of you Applause


m0nkeymafia is confused!  Applause

nutballs

i must have been multitasking when I posted this. I do what you suggested perk, creating the object with the database vars. I don't know why I had them hard coded into the class. This is what I actually have.
function __construct($s,$d,$u,$p) {
      $GLOBALS['database'] = &$this;
      $this->opendb($s,$d,$u,$p);
  }

perkiset

@ MM - The Kaptain used to talk 3rd person for every post, it was hilarious

@NBs - figured you did, thought that was pseudo code. Still recommend the "don't instantiate if already created" bit tho...

nutballs

i agree. thats the kind of thing I usually leave out because i am in a rush/lazy/confused and regret later. adding now... to all my classes that use the $GLOBALS.

although this did make me realize something. My db class could not instantiate more than once anyway to connect to more than 1 db i think? because I use the $GLOBALS.
$GLOBALS['database'] = &$this;
is set the first time the object is created, so if i tried to make another object, $dbother, then it would lose the first object pointer stored in $GLOBALS['database'] because the new pointer would be written.

err. i gotta rethink that. for my other classes, they are pure singletons, and I want it that way, but for the DB class, singleton is not acceptible. 99% of the time it should be, but there is that 1% that I should be prepared for.

nutballs

ok actually to make it a non-singleton (though it technically still is) I added the ability to set the reference name as you construct it. This is my actual code, unmodded, so its using other classes you are not aware of obviously.

$database = new database($config->dbserver,$config->dbdatabase,$config->dbuser,$config->dbpassword,'database1');
$database = new database($config->dbserver,$config->dbdatabase,$config->dbuser,$config->dbpassword,'database2');

function __construct($s,$d,$u,$p,$name) {
//Server,database,username,password,$GLOBALS name
if ($GLOBALS[$name])
{
$messages = &$GLOBALS['messages'];
$messages->adderr('database.class.

php

  $GLOBALS[''.$name.''] is being constructed more than once.');
}
else
{
$GLOBALS[$name] = &$this;
$this->opendb($s,$d,$u,$p);
}

  }

perkiset

Way better. That looks good man

nutballs

the only problem is references from within other classes, specifically my ApplicationSpecific class. Since the object is created in the main document, the name of the $GLOBALS is not knows to the classes which might depend on it. However, since the database is never used by any of my other base classes, I guess it doesnt matter. and if it does, I will just create a local instance.

perkiset

Two ways to handle that - either use generic names that you always rely on (I use utilDB) or use an array that is held by GLOBALS that has a list of available dbs ie:


<?

php

 
$db = &$GLOBALS['utilDB'] = new dbConnection($host, $user, $pass, $db);
$GLOBALS['dbHash']['utilDB'] = 'utilDB';
?>


Now if you iterate through GLOBALS['dbHash'] you'd have the names of all global DBs you'd created. If you had your own "standard" list of db objects, then if an object encountered one that was missing it could create it. I realize that second line looks a little weird, but it enables you to look 2 different ways for stuff, because of both the trueness of "dbHash/utilDB" and if you iterate using a foreach($GLOBALS['dbHash'] as $name=>$value) you can get them all.

Sorry, probably not terribly lucid, still pretty whupped from this weekend.

Applause
/p

nutballs

no that makes sense. I think however, for my purposes, I am OK with strong-naming of the handles because of what this is actually being used for, which is a strict framework to build sites in. Basically i have a bunch of "consistent" classes that are always available (if used of course) and then I have 1 giant application class (though there may be subclasses) that contains every single site specific piece of code. The rest then is generic, and as such, can be upgraded globally, and if it works in 1 place, it will work in all places. The database stuff will never be used by the framework classes, except if the entire database connection is created and destroyed within the class. So as a result, something like a traffic tracking class will have its own personal database object, named something random to prevent collisions and will never be accessed from outside that class. The only time that a database object will need to be accessed from more than 1 class/scope, is the MAIN junk, ie, the page level code, and the application class which is always custom so it is not an issue. So... i think I have my framework. YEAY!

perkiset

Right on, 'grats NBs! I know how that was for me when I finally felt like I had my basic framework installed and could go forward again - it's great.

Contrarian thought: I use 1 DB connection almost exclusively and recommend it, here's why:

I had a site that used many connections and I got slammed with traffic... and prompty started getting MySQL connection failures. The problem is that when you create a new connection, it's <i>literally</i> a new connection and you're using up MySQL connection handles. Since

PHP

  is not threaded, it is fair to say that you're only doing one thing at any given time... so most of the time you can distill your work down to doing this or that with the DB at any given moment... and poof, you only need one DB connection. When you need a master/detail or more then you can use more, but making a personal protocol of trying to use only one DB connection at a time you'll minimize impact on your server.

Where I have FK referential integrity tables that are small and such, I'll check my cache to see if I already have it, if not, go read all rows for <that> query, then store it as a hashed array in the persisent memory cache rather than going to the DB as well - this REALLY improves my performance.

As I get deeper into my class libs I am more likely to let "everyone have their own connection" which is a perfectly fine MO, except when you may get the shit beaten out of you by the engines... which is exactly what took me down.

Just another Applause,
/p

nutballs

That is my MO as well. I just use one connection whenever I can. The only time I dont is when I need to hit more than 1 db at the same time. But whenever possible, I reuse connections, which is why i really wanted a global pointer to the database object.


Perkiset's Place Home   Politics @ Perkiset's