2
\$\begingroup\$

Under sage from another CR post I'm crafting an OOP MySQL connection/query class. Nothing new, but a place to start plying OOP PHP. Here is the current design,what would aid speed and portability?

conf/config.php

<?php

//Inlcude the Data Access Layer: Db
require_once (dirname(dirname(__FILE__)) . '/inc/class/dbc.php');


//DB Constants...
define('DB_HOST','dbhost');
define('DB_USER','user');
define('DB_PASS','pass');
define('DB_NAME','dbname');


?>

inc/class/dbc.php

<?php  

/**
* 
*/
class Db            
{
    public $mysql;

    function __construct()
    {
        $this->mysql = new mysqli (DB_HOST, DB_USER, DB_PASS, DB_NAME) OR die ('Could not connect to MySQL: ' . mysqli_connect_error() );

//adding custom error checking:

    }// End Constructor


}//End Class Definition

index.php

<div id="todo">
<?php

                require_once(dirname(__FILE__) . '/conf/config.php');
                $db = new Db();
                $query = "SELECT * FROM todo ORDER BY id asc";
                $results = $db->mysql->query($query);

                if($results->num_rows) {
                    while($row = $results->fetch_object()) {
                        $title = $row->title;
                        $description = $row->description;
                        $id = $row->id;

    ?>          

</div>
\$\endgroup\$
1
\$\begingroup\$

This code binds your Db object to the global constants. Its going to be difficult to connect to more than 1 database. Your DB class isn't doing anything for you.

The solution to this is: injection. You should pass in the settings for the Db in the constructor. Below is the PDO class from my framework which I think is serving a similar role to what you are trying to achieve with your Db class. The injection is achieved by accepting parameters in the constructor ($setup).

/// PDO wrapper class to ensure DB implements the Evoke Core DB interface.
class PDO extends \PDO implements \Evoke\Core\Iface\DB
{
   public function __construct(Array $setup)
   {
      $setup += array(
         'DSN'      => NULL,
         'Options'  => array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION),
         'Password' => NULL,
         'Username' => NULL);

      if (!isset($setup['DSN']))
      {
         throw new \InvalidArgumentException(__METHOD__ . ' requires DSN');
      }

      if (!isset($setup['Password']))
      {
         throw new \InvalidArgumentException(__METHOD__ . ' requires Password');
      }

      if (!isset($setup['Username']))
      {
         throw new \InvalidArgumentException(__METHOD__ . ' requires Username');
      }

      parent::__construct($setup['DSN'],
                          $setup['Username'],
                          $setup['Password'],
                          $setup['Options']);
   }
}

There are a number of differences with this approach:

  1. The Db class is a Db type object (extends PDO).
  2. Common database type functions are ensured (implements Iface\DB).
  3. Setup for the database is injected (with the setup parameter). This means that many databases could be connected to each with a different set of parameters injected.
  4. Validity of the setup is enforced.

By creating an interface we can pass any type of object that implements the interface for use as our Db object. This means our code is decoupled from the specific type of database object (I could replace PDO with mysqli very easily if I wanted to).

function index($db)
{
   if (!$db instanceof \Iface\DB)
   {
      throw new \InvalidArgumentException(__METHOD__ . ' we need a Db object.');
   }
}

Personally I have the small PDO wrapper you saw above and then a further abstraction for SQL statements. With everything all of the dependencies are injected (normally in the constructor). You can see more of my Db objects here. Notice how the SQL class is injected with a Db (any sort of DB that implements the DB interface):

class SQL implements \Evoke\Core\Iface\DB
{
   protected $inTransaction = false;

   protected $setup;

   /// Class constructor
   public function __construct($setup=array())
   {
      $this->setup = array_merge(array('DB' => NULL), $setup);

      if (!$this->setup['DB'] instanceof \Evoke\Core\Iface\DB)
      {
         throw new \InvalidArgumentException(__METHOD__ . ' needs DB');
      }
   }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.