Having such class is a really good idea, but unfortunately moving from mysql_*
API to mysqli
class is not so simple. It requires a large code rewrite and change in thinking.
If you are planning the upgrade from mysql_*
API it probably means you were using PHP 4 until now. If you were using PHP 5, you were using PHP 4 way of thinking. PHP has come a long way since then. We now have proper classes, namespacing, better error reporting, etc. When it comes to database interactions we now have two new extensions: mysqli and PDO. Out of these two you should be using PDO. However, if you are using a wrapper class like the one you are trying to create changing from mysqli to PDO should be very easy. For this reason alone such a wrapper class is a good idea.
The primary reason for mysqli extension was to keep a familiar syntax of the old extension and add necessary new features such as prepared statements and proper error reporting. If you were used to putting PHP variables directly into SQL queries, you must change your way of thinking. You should now use parameterized queries and bind the values separately.
A simple example of what your improved class could look like is this:
<?php
class DBController {
/**
* mysqli instance
*
* @var \mysqli
*/
private $mysqli;
public function __construct(
$host = null,
$username = null,
$passwd = null,
$dbname = null,
$charset = 'utf8mb4',
$port = null,
$socket = null
) {
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$this->mysqli = new \mysqli($host, $username, $passwd, $dbname, $port, $socket);
$this->mysqli->set_charset($charset);
}
public function runQuery(string $sql, array $params = []): ?array {
$stmt = $this->mysqli->prepare($sql);
if ($params) {
$stmt->bind_param(str_repeat("s", count($params)), ...$params);
}
$stmt->execute();
if ($result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_BOTH);
}
return null;
}
}
Warning: This is not a full implementation of such wrapper class. You most likely need to implement other methods and add more logic as per your needs. This is only for demonstration purposes.
First, in the construct method, we should execute 3 steps. Enable error reporting, create an instance of the mysqli
class and set the correct charset (use utf8mb4
which was added in MySQL 5.5 and is now the standard charset).
Your runQuery()
method now accepts 2 arguments. The first one is your SQL query with placeholders instead of interpolated values, and the second one is an array of the values to be bound.
Most likely you do not need selectDB()
and you definitely do not need numRows()
. If you want to know the number of rows in your retrieved array, you can count them in PHP using count()
.
Using such class is very simple.
$db = new DBController('localhost', 'username', 'password', 'db_name');
$result = $db->runQuery('SELECT Id, Name FROM table1 WHERE uuid=?', ['myuuid']);
if ($result) {
// Get the name of found record
echo $result[0]['Name'];
} else {
echo 'No records found';
}
If you wanted to switch the implementation to PDO, you can replace the class without changing the way you use it.
class DBController {
/**
* PDO instance
*
* @var \PDO
*/
private $pdo;
public function __construct(
$host = null,
$username = null,
$passwd = null,
$dbname = null,
$charset = 'utf8mb4',
$port = null,
$socket = null
) {
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset;port=$port;socket=$socket";
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$this->pdo = new PDO($dsn, $username, $passwd, $options);
}
public function runQuery(string $sql, array $params = []): ?array {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
}
Warning: This is not a full implementation of such wrapper class. You most likely need to implement other methods and add more logic as per your needs. This is only for demonstration purposes.