views:

274

answers:

4

Hello,

I have a database abstraction layer that starts with a base class like so:

class DB {
  function DB() {
    $this->host = "xxx";
    $this->db = "xxx";
    $this->user = "xx";
    $this->pass = "xx";
    $this->dbh = mysql_connect($this->host, $this->user, $this->pass);
    mysql_select_db($this->db);
    // etc
  }
}

class DBI extends DB {
  // etc
}

Now I would like for the child classes to inherit the database handle but not the credentials. I tried (in the DBI class)

        function DBI (){ 
      $this->host ='';
      $this->db ='';
      $this->user ='';
      $this->pass ='';
     }

But that kills the handle; not sure why. Also tried

class DBI extends DB {
    var $host ='';
    var $db ='';
    var $user ='';
    var $pass ='';
}

to no effect.

So I am wondering if what I ought to do is just move the database connection out of the class altoghether? Just start the class file with a connection and leave it at that?

Opinions?

Thanks

JG

+1  A: 

If you don't want a child class to inherit a property, you can declare it as private. This only works for PHP 5:

class DB {

  private $host = "xxx";
  private $db = "xxx";
  private $user = "xx";
  private $pass = "xx";

  function DB() {
    $this->dbh = mysql_connect($this->host, $this->user, $this->pass);
    mysql_select_db($this->db);
    // etc
  }
}

However, I wouldn't recommend this approach. Database settings are better off stored in a configuration file. In this way, it's easier to re-use your code between applications.

It's still very common to make a configuration variable be an array inside a file named config.php, and then use that array as a global in functions that require it. However, it's also a good idea to stay away from globals when possible. There are some good designs of how to manage a configuration class out there, for instance Zend_Config. You can get some good ideas from how they've done it.

zombat
When I do it that way and dump a child object I still get the values, just flagged as private:Incentive Object( [table] => membership_incentivesV2 [changedVals] => Array ( ) [connectionError] => [host:private] => xxx [db:private] => xxx [user:private] => xxx [pass:private] => xxx [dbh] => Resource id #4)
jerrygarciuh
Don't confuse the output of var_dump with actual class-member visibility. Yes, the data is there, but instances of `DBI` cannot read variables declared as private in `DB`
Peter Bailey
+3  A: 

Then don't make them member variables

<?php
class DB
{
  var $dbh;

  function DB()
  {
    $this->dbh = mysql_connect( "xxx", "xxx", "xx" );
    mysql_select_db( "xx", $this->dbh );
    // etc
  }
}

class DBI extends DB {
  // etc
}

or switch to PHP5 and make them private

<?php
class DB
{
  private
      $host = "xxx"
    , $db   = "xxx"
    , $user = "xx"
    , $pass = "xx"
  ;

  protected $dbh;

  public function __construct()
  {
    $this->dbh = mysql_connect($this->host, $this->user, $this->pass);
    mysql_select_db( $this->db, $this->dbh );
    // etc
  }
}

class DBI extends DB {
  // etc
}

and I should not that you need to remember you pass your connection handle to functions like mysql_select_db() to stay multi-connection safe.

EDIT!

But that kills the handle; not sure why.

Because PHP doesn't cascade constructors (the parent class' constructor isn't implicitly called). That means DB::DB() isn't automatically called when you create an instance of DBI. So you have to do that explicitly. So I guess this is another option but I don't really like it

class DBI extends DB
{
  function DBI()
  {
    // Call the parent constructor
    parent::DB();

    // Now empty these member variables
    $this->host = '';
    $this->db   = '';
    $this->user = '';
    $this->pass = '';
  }
}
Peter Bailey
+2  A: 

Why not pass the database settings in via the constructor:

function DB($host, $db, $user, $pass) {
    $this->host = $host;
    $this->db = $db;
    $this->user = $user;
    $this->pass = $pass;
    $this->dbh = mysql_connect($this->host, $this->user, $this->pass);
    mysql_select_db($this->db);
}

Then you can do

function DBI() {
    parent::DB('xxx', 'xxx', 'xxx', 'xxx');
}

(In both PHP4 and PHP5, the parent constructor will not be called implicitly. This is why your handle is "killed" in your DBI subclass; it never gets initialized. What you really need is to switch to PHP5, though :)

Øystein Riiser Gundersen
A: 

In the end the simplest approach is just to move the connection out of the classes. If I start off the class file with the connection then the handle is available to all the classes without making $dbh a class attribute.

jerrygarciuh