0

Sorry for the stupid question am a newbie to oop in php...i have a proble wiriting a mysqli class thet returns a connection handler that enable me the connection handler in other classes/methods. i run a small procedural blog n wanted to convert to oop. heres a my working code example. please refactor for me where necessary. Thank in advance.

$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
  public function getConfig($id, $db_link) // thanks cbuckley
 {
   $db_link = $this->db_link;
   $res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
   $row = mysqli_fetch_array($res);
   return $row['option'];
  }    
}

i have defined the constants already and the connection is successful but the select is not working. on the index page this goes

include('inc/dbc.php'); 
$db = new MyDB(); 
echo $db->getConfig(1, $db_link);  

any help is appreciated

hakre
  • 193,403
  • 52
  • 435
  • 836
jcobhams
  • 796
  • 2
  • 12
  • 29
  • Is there a reason why you do not use PDO? Many PHP users are speaking about that PDO is more easy to use for them and it offers similar features than mysqli and some more next to it? Just asking, would be interesting to know. – hakre Sep 19 '12 at 13:47

3 Answers3

6

Your question is not very specific, and I have the feeling you're not really aware what your concrete problems are. You've already accept an answer that gives you some code but puts you in the wrong direction as it does not solve your underlying problem and wastes code.

The first thing you should know if you want to make use and benefit of the object oriented interface of PHP's mysqli extension is, that the Mysqli class represents the database connection (the "link" as it was named for a procedural approach) already:

require('inc/dbc.php');

$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);

That's already it. Sure you might want to use some error handling here:

if ($dbConnection->connect_error)
{
    throw new Exception(
       sprintf('(#%d) %s', $dbConnection->connect_errorno,
                $dbConnection->connect_error)
    );
}

Throwing exception instead of let's say die('message') is done, because you can easily create an exception handler so that you can display a more useful response to the user from within a central place instead of handling each exceptional error-case where it appears (actually at the place where die would be).

You can also log and mail the backtrace so you can fix things more easily. Naturally you do not need to use exceptions, however the rule of thumb is to use die only in scripts you throw away in let's say a week and it does not work well with object oriented design.

As you will need this code anyway in all places where you will need your database connection, you can create your own connection object to bring those parts together as they belong together:

class DatabaseException extends Exception
{
}

class DatabaseConnection extends Mysqli
{
    public function __construct($host, $user, $password, $database = "", $port = NULL, $socket = NULL) {

        parent::__construct($host, $user, $password, $database, $port, $socket);

        $this->throwConnectionExceptionOnConnectionError();
    }

    private function throwConnectionExceptionOnConnectionError() {

        if (!$this->connect_error) return;

        $message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);

        throw new DatabaseException($message);
    }
}

The usage is actually pretty straight forward and very much the same, only the name of the class varies and it's definition needs to be loaded:

require('inc/dbc.php');
require('inc/database.php');

$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);

As written, the connection object already represents your database connection. So every part in your application that needs it, has to ask for it. Let's review your example function:

function getOption($id, $db_link)
{
   // $db_link = $this->db_link;
   $res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
   $row = mysqli_fetch_array($res);
   return $row['option'];
}

I renamed the function and I commented the first line, even this might be what you want. Actually, if that function would be part of the DatabaseConnection object, it could work like this:

class DatabaseConnection extends Mysqli
{
    ...

    public function getOption($id) {
        $statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
        $statement->bind_param('i', $id);
        $statement->execute();
        $statement->bind_result($option);
        $statement->fetch();
        $statement->close();
        return $option;
    }

As this example demonstrates, the database connection is already there. However, this is not advisable. Imagine you not only have options but this and that and such and what not more. You would create one function after the other all in one class. Well for a little application that might even so work right, but imagine more and more. You would get one very large class that is responsible for many things. So it would be bad to do this, even if you can use $this already to prepare the statement.

Also take note that you should prepare statements. This has been answered here numerous times, if you're not used to it, read about it, it's worth the lines. There are better ways to not repeat code (DRY: Don't repeat yourself) while stepping into object oriented (you should even already do this with procedural).

So as to have this all in one class would be a problem, you instead put it in a class of it's own:

class DatabaseModelBase
{
    protected $connection;

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

    protected function prepare($query) {
        $connection = $this->connection;
        $statement = $connection->prepare($query);
        if (!$statement) {
            throw new DatabaseException(
                sprintf('(%s) %s', $connection->error, $connection->errno)
            );
        }
        return $statement;
    }
}

class Option extends DatabaseModelBase
{
    public function find($id) {
        $statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
        $statement->bind_param('i', $id);
        $statement->execute();
        $statement->bind_result($option);
        $statement->fetch();
        $statement->close();

        return $option;
    }
}

This has some extended error handling again, because most often mistakes are made in the SQL query. And as you can see the individual function to fetch some specific data is placed in it's own class. You can use such classes to group the fetching and updating for specific datatypes.

Usage in full:

$dbConnection = new Connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);

$option = new Option($dbConnection);

$optionValue = $option->find(1);

echo $optionValue; # value for option with ID1

The names of the Option object probably is not well, I tried to keep the example lightweight but also offer some separation. For other scenarious you might want to prefer some different kind how to access the db connection, because it is injected into Option via it's constructor, Option does not deal any longer with the details how the database connection is being created.

For example you can make the database connection object more smart only to connect to the database the first time prepare or query is actually used with it. So that requests to your website that do not need a database connection would not needlessly connect to the database.

You find more examples in other questions and you might want to learn about dependency injection. Also you always want to keep things apart from each other, so you have some objects that are only lightly connected to each other.

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Hmmmm...well hakra this is an extensive answer to my question.. Thank you soo much I will put this code to use and get back to you concerning the outcome and any issues I may encounter...thank you – jcobhams Sep 20 '12 at 18:35
  • 1
    Yes it's a little extensive and I suppose the second part is a bit fuzzy. That part is mainly also influenced how you would do it / your style, I think the first part is more important to understand for the "basics" of Mysli "OO". It's a bit extensive because I think you put multiple things together you see as problems, maybe even as one problem. Try to keep problems a bit more isolated, that often helps to find solutions easier. It's something that comes with practice, and will never stop in programming, regardless how short or long your practice is. – hakre Sep 21 '12 at 08:52
  • Thank you again pls could you give me a full working class to work with..join all the necessary functions and their calls on the respective objects...thank you – jcobhams Sep 21 '12 at 09:58
  • You have it in the example that follows the sentence *"create your own connection object to bring those parts together as they belong together:"* - that is the whole database connection class. And it also should work, the usage example is the last example. Note also that your constant names were a bit misleading and I changed them. – hakre Sep 21 '12 at 10:05
  • Still very confusing to use..sorry for my. Dull interactions an terrible bad and unexperienced in oop..the code after the create your own connection line?..also do I jus copy that and paset on my editor and the usage examples and the config value will be returned? – jcobhams Sep 21 '12 at 10:17
  • Also about the constatn names wher did u apply changes.so that I can take note of it!..pls let me know wher the working code starts and stops..from db connection to returned config value..thanks:) – jcobhams Sep 21 '12 at 10:19
  • Here is the example in full. You would have it in different files, I left some comments: https://gist.github.com/3760815 – hakre Sep 21 '12 at 10:32
  • Could you please explain where the hell the 'i' comes from in $statement->bind_param('i', $id); I've tried to use the code above but all I get returned is 'Call to a member function bind_param() on a non-object' – jezzipin Jan 30 '13 at 14:03
  • @jme1988: The `'i'` is explained here: http://php.net/mysqli-stmt.bind-param - which is the function that should exist on a statement object (see the ***types*** parameter which has a table that shows which letters you can use). Your error message however tells that the object is not there. So the cause of the error is not the `i` - just saying, maybe my code example is only exemplary and not working code (can be the case as no online codepad has been linked), so treat code you find online with care. – hakre Jan 30 '13 at 14:05
  • I don't understand from your code above though where you are actually defining that $id should be used. What would happen if you had multiple variable to replace in the MySQLi query string. How would it know which to replace? You should always post working code on StackOverflow. – jezzipin Jan 30 '13 at 14:11
  • @jme1988: No, SO is not a code posting help website, it's perfectly okay if the code *examples* given outline the situation. If you're uncertain about a specific function used, please read about it in the manual. There you also find additional code examples you can easily test your own. – hakre Jan 31 '13 at 06:34
3

I would suggest moving the connect to the database also inside the class:

class myDB extends mysqli
{
  private $link;

  public function Connect()
  {
    $this->link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
  }

  public function getConfig($id) // thanks cbuckley
  {
     $res = mysqli_query($this->link,"SELECT * from config where id='$id'");
     $row = mysqli_fetch_array($res);
     return $row['option'];
   }    
}

And use it like this:

include('inc/dbc.php'); 
$db = new MyDB();
$db->Connect(); 
echo $db->getConfig(1);
JvdBerg
  • 21,777
  • 8
  • 38
  • 55
  • woooooooow.....thanks bro i owe you one...it worked perfectly!!!...hpe if u dont mind if we become friends as i see lots of trouble on my oop journey...Thank you lots. – jcobhams Sep 19 '12 at 12:12
  • This is a bit complicated, and there is no reason why the `myDB` class extends from `mysqli` here obviously. So why did you do that? Don't you think it's misleading for the developer who asked? – hakre Sep 19 '12 at 13:06
  • Read up on OO, search for encapsulation, separation of concerns, testable code etc etc. Programming is a serious profession. – JvdBerg Sep 19 '12 at 13:09
  • @JvdBerg: Sure, but what you do here is totally the opposite. That's actual the reason why I asked. What is your reason? Professionalism is not. First of all using the procedural interface of Mysqli is - well - procedural not object oriented. You can argue that you encapsulate that away, however that's so much totally superfluous as you extend from `mysqli`, using the parent's ctor and `$this` would have done it, wouldn't it? And then testable code. Database configuration as global static constants, how can one not put a warn on that? And the list can go on and on. So what is your reason? – hakre Sep 19 '12 at 13:38
  • I am trying to help someone who is making his first steps in OO programming! If you want to discuss it, you can always open a question. – JvdBerg Sep 19 '12 at 13:44
  • @JvdBerg: Sure, first steps in OOP, that's why you suggest to use procedural interface of mysqli. I see, there is much you have to share. – hakre Sep 20 '12 at 06:44
2

I recommend you to Wrap the mysqli class in a new Class instead extending it: For those Classes, where you need the Configuration, just include the Configuration with Dependency Injection. This brings you the Benefit, that the Code, where you need the Configuration, don't need to know about the Way, Configuration get its values. If you later decide to parse Configuration from a iniFile, you only need to change the Configuration-Class or even better, write a new Class which implements ConfigurationInterface and inject the new ConfigurationClass.

class Configuration implements ConfigurationInterface{
        private $mysqli;

        public function construct(mysqli $mysqli) {
            $this->mysqli = $mysqli;
        }

        public function get($key) 
        {
            // You should escape this query to prevent SQL-injection
            $res = $this->mysqli->query("SELECT * from config where id='$key'");
            $row = $res>fetch_array();
            return $row['option'];
        }
    }

interface ConfigurationInterface {
    public get($key);
}

Use it like this:

$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);

var_dump($config->get(0));
mineichen
  • 470
  • 2
  • 11
  • thank you for the advice but i dont really understand your logic. Note an a newbie in this paradigm of php programming..please simplyfy your code..thank you – jcobhams Sep 19 '12 at 12:45
  • I hope it's clearer now... About the escaping im sure you'll find in the API, i don't really know mysqli because i use PDO instead – mineichen Sep 19 '12 at 13:05