I made the following class to wrap mysqli
for PHP using prepared statements. It seems to work well, but I was hoping to get opinions (on overall structure, performance, usage, etc.). Thanks for the insight.
<?php
class database {
private $conn, $stmt, $arr, $eof=true, $error;
public function __construct($host, $user, $pass, $db) {
$this->conn = mysqli_connect($host, $user, $pass, $db);
if(mysqli_connect_errno()) $this->error = mysqli_connect_error();
}
public function __destruct() {
if($this->stmt) mysqli_stmt_close($this->stmt);
mysqli_close($this->conn);
}
/** Executes a prepared SQL query on the database
*
* The second argument (optional) is the types list, followed by the parameters
* e.g. query('SELECT * FROM table WHERE id = ? OR name = ?', 'is', 5, 'Joe')
*
* @param string $query is the sql statement to execute
* @return mixed false on error,
* true on successful select, or
* the number of affected rows
*/
public function query($query) {
// create a new prepared statement
$stmt = mysqli_prepare($this->conn, $query);
if(!$stmt) {
$this->error = mysqli_error($this->conn);
return false;
}
// apply the arguments if any exist
if(func_num_args() > 2) {
$args = array_slice(func_get_args(), 1);
$refs = array();
foreach($args as $key=>&$value) $refs[$key] = &$value;
call_user_func_array(array($stmt, 'bind_param'), $refs);
}
// run the query
$stmt->execute();
if($stmt->errno) {
$this->error = mysqli_error($this->conn);
return false;
}
// if the query was not a select, return the number of rows affected
if($stmt->affected_rows > -1) {
$rows = $stmt->affected_rows;
mysqli_stmt_close($stmt);
return $rows;
}
// close any previous statement
if($this->stmt) mysqli_stmt_close($this->stmt);
$this->stmt = $stmt;
$this->eof = false;
// bind the results to the associative array
$this->arr = array();
$refs = array();
$meta = mysqli_stmt_result_metadata($stmt);
while($column = mysqli_fetch_field($meta)) {
$refs[] = &$this->arr[str_replace(' ', '_', $column->name)];
}
call_user_func_array(array($stmt, 'bind_result'), $refs);
// make the first result set available
$this->next();
return true;
}
// fetches the next row
public function next() {
if($this->stmt) {
$ret = mysqli_stmt_fetch($this->stmt); // populates $this->arr
$this->eof = ($ret !== true);
if($ret === false) $this->error = mysqli_error($this->conn);
}
}
// returns an associative array of the results
public function results() {
// must make a copy when returning the entire array because
// the array holds references that may be updated
$ret = array();
foreach($this->arr as $key=>$value) $ret[$key] = $value;
return $ret;
}
// return the value for the specified field
public function result($field) { return $this->arr[$field]; }
public function __get($field) { return $this->result($field); }
// returns true if eof has occured or an error
public function eof() { return $this->eof; }
// returns the number of rows in the result set
public function count() { return ($this->stmt ? $this->stmt->num_rows : 0); }
// returns the last error message, if clear is true, clears the error as well
public function error($clear=false) {
$err = $this->error;
if($clear) $this->error = '';
return $err;
}
}
?>