3

I have a basic Database class, and it has a mysqli property (an object itself) which contains the connection information. Other classes uses this class to read and manipulate the database.

There are built-in functions in any database connection object (in this case, PHP's mysqli::multi_query, mysqli::next_result etc.), that I need to use in other classes.

The problem is that I really do not want to set the connection property as public since I believe it is a bad practice to do so in any property, especially not one with connection information.

So what should I do? Should I set it to public anyway, or should I create manually a function for each built-in function I need to use?

1 Answer 1

4

The whole point of wrapping a core PHP database driver is to provide your custom interface for handling database requests. Making the mysqli property public completely defies the purpose and you wouldn't really need your custom class in the first place.

The best approach would be to create a DatabaseInterface, have class or classes implement it, classes, which, preferably in their constructor, take a core PHP database driver (be it mysqli or PDO) and use the DatabaseInterface as parameters for classes which require database interaction.

This way you provide your own abstraction, over which you have full control, and are also not limited to single implementation.


More details and implementation example

In PHP you have generally two recommended options for database connection.

  • using PDO
  • using mysqli

The problem is PDO and mysqli provide different interface to querying, creating transactions, so if you used for example mysqli in your application directly and then wanted to switch to PDO, you would have to refactor every single database call in your app.

Use interfaces for abstraction

You create an interface, which will represent your very own interface for database calls. Here is a very simple example how some of its methods may look.

interface MyDatabase
{
    public function beginTransaction();
    public function commitTransaction();
    public function doQuery($sql);
}

Right now you want to use mysqli, so you create a new class, MyMySQLiDriver, which will implement the MyDatabase interface and either take a mysqli object in its constructor as a parameter, or you can use the procedural-programming mysqli_* functions.

class MyMySQLiDriver implements MyDatabase
{
    protected $mysqli;

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

    public function beginTransaction() { /* use $this->mysqli here */ }
    public function commitTransaction() { /* use $this->mysqli here */ }
    public function doQuery($sql) { /* use $this->mysqli here */ }
}

Anywhere else in your code, if you want to use a database, you are going to pass an object of MyDatabase (the interface) type as a parameter and use its methods.

function IAmUsingTheDatabase(MyDatabase $db)
{
    $db->beginTransaction();
    $db->doQuery("SELECT * ...");
    $db->commitTransaction();
}

Note that the IAmUsingTheDatabase has no idea whether you are using PDO, mysqli or anything else. It wants to use the database and it uses the interface you provided.

As I have said in the comments under this post, if, in the future, you don't want to use the MyMySQLiDriver anymore, you create a new class, be it MyPDODriver or anything else, which will again implement MyDatabase interface.


Where to go from here

You can study more on this topic under Inversion of Control (this is directly tied to Dependency injection and benefits greatly from the Strategy pattern).

7
  • But what would be exactly the structure of that interface? Oct 20, 2015 at 11:41
  • Take a look at YAGNI. You shouldn't make methods just because you think one day you are going to need it. If you need a method for something, add and implement it, but in your case, they will be fairly similar to the core methods.
    – Andy
    Oct 20, 2015 at 12:02
  • But why create an interface? I could just stay with my class and create those functions I need. Sorry if it is a silly question, I am pretty new to OOP. Oct 20, 2015 at 14:51
  • @Sipo You want to create an interface and have a class implement said interface to be able to swap out the implementation, should you ever, without changing anything else. Let's say you decide to use PDO instead of mysqli in 2 years, you will just create a new database driver implementing DatabaseInterface which will use the PDO and simply change in your config you no longer want to use the one using mysqli but the one which uses PDO instead. And everything will still work, because the database contract is guaranteed by the interface and not a specific class.
    – Andy
    Oct 20, 2015 at 15:04
  • Could you add some basic example to your answer? Thanks. Oct 20, 2015 at 15:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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