Below is the code for a database class that wraps around a small set of the features that the mysqli
extension provides. I'm looking for ways to improve its efficiency. Which parts of the code seem hack-ish and how can I make it more structured and organized?
class Database extends Component
{
private static $mysqli = null; // MySQLi object
/* Connect to the database */
public static function init()
{
if (Config::read('Database.enable'))
{
if (!self::connect(Config::read('Database.connections')))
trigger_error('Database::connect() failed : Unable to connect to database', E_USER_ERROR);
}
}
/* Close the database connection upon script determination */
public function __destruct()
{
if (self::$mysqli)
self::$mysqli->close();
}
/* Returns the type label (i, d, s, b) of an array of MySQLi input parameters */
private static function getTypeLabel(array $args)
{
$return = '';
foreach ($args as $input)
{
if (is_int($input))
$return .= 'i';
else if (is_double($input) || is_float($input))
$return .= 'd';
else if (is_string($input))
$return .= 's';
else
$return .= 'b';
}
return $return;
}
/* Returns whether the MySQL connection has been established */
public static function connected()
{
return is_resource(self::$mysqli);
}
/* Returns the MySQL connection resource */
public static function obj()
{
return self::$mysqli;
}
/* Pass an array of login credentials and attempts to connect to the database */
public static function connect($db_list)
{
foreach ($db_list as $db)
{
self::$mysqli = @(new mysqli($db['host'], $db['user'], $db['pass'], $db['db']));
if (mysqli_connect_errno())
{
self::$mysqli = null;
continue;
}
break;
}
return self::$mysqli !== null;
}
/**
* Execute a query given a query string and passed parameters. Returns
* the result array or the number of affected rows if it is an update, insert
* or delete query. Returns null and triggers error if query failed.
* This function basically combines executeQuery() and prepareQuery()
* Example:
*
* $result = DB::query('SELECT * FROM my_table WHERE id = ?', $id);
* $num_rows = $result['num_rows'];
* foreach ($result['rows'] as $row)
* {
* echo $row['field'];
* }
*
**/
public static function query($query)
{
// If there is no connection to the MySQL server, then return null
if (!self::$mysqli)
return null;
if ($query = self::$mysqli->prepare($query))
{
$results = array();
// Build args array and call mysqli_stmt::bind_param
if (func_num_args() > 1)
{
$fga = func_get_args(); // For ASO servers (PHP 5.0.2), this is necessary
$args = array_merge(array(func_get_arg(1)), array_slice($fga, 2));
$args_ref = array();
$args_ref[0] = self::getTypeLabel($args);
foreach ($args as $k => &$arg)
$args_ref[] =& $arg;
call_user_func_array(array($query, 'bind_param'), $args_ref);
}
// Execute query
$query->execute();
// Most likely due to syntax errors
if ($query->errno)
{
trigger_error(self::$mysqli->error, E_USER_ERROR);
return null;
}
// If the query was insert, update or delete, then return affected rows
if ($query->affected_rows > -1)
return $query->affected_rows;
// Build results array and call mysqli_stmt::bind_result
$params = array();
$meta = $query->result_metadata();
while ($field = $meta->fetch_field())
$params[] =& $row[$field->name];
call_user_func_array(array($query, 'bind_result'), $params);
// Fetch results and store them in returned array
while ($query->fetch())
{
$r = array();
foreach ($row as $key => $value)
$r[$key] = $value;
$result[] = $r;
}
$query->close();
return count($result) > 1 ? $result : $result[0];
}
trigger_error(self::$mysqli->error, E_USER_WARNING);
return null;
}
}