As I said in the segment you just read, it's perfectly possible to use an undeclared static property within the "MySQLiWrapper" class to prevent multiple, unnecessary connections to MySQL. But how will this be done? Creating the mentioned variable only within the "connect()" method will do the trick. If this sounds a bit confusing to you, then study the modified version of the class, which now looks like this:
class MySQLiWrapper extends MySQLi {
private static $_instance = NULL; private $_config = array();
// return Singleton instance of MySQL class public static function getInstance(array $config = array()) { if (self::$_instance === NULL) { self::$_instance = new self($config); } return self::$_instance; }
// private constructor private function __construct(array $config) { if (count($config) < 4) { throw new Exception('Invalid number of connection parameters'); } $this->_config = $config;
}
// prevent cloning class instance private function __clone(){}
// establish a connection to MySQL public function connect() { static $connected = FALSE; // if no previous connection exists, connect to MySQL if ($connected === FALSE) { list($host, $user, $password, $database) = $this->_config; parent::__construct($host, $user, $password, $database); if ($this->connect_error) { throw new Exception('Error connecting to MySQL : ' . $this->connect_errno . ' ' . $this->connect_error); } // connection is successful $connected = TRUE; unset($host, $password, $database); } }
// perform query public function runQuery($query) { if (is_string($query) AND !empty($query)) { // lazy connect to MySQL $this->connect(); // run the specified query if ((!$this->real_query($query))) { throw new Exception('Error performing query ' . $query . ' - Error message : ' . $this->error); } return new MySQLi_ResultWrapper($this); } }
// get insertion ID public function getInsertID() { return $this->insert_id; }
// close database connection public function __destruct() { $this->close(); } } Since most of the methods that compose the "MySQLiWrapper" class remain the same, I suggest you focus your attention only on the "connect()" method. This is the one that has been modified. In this case, the method internally creates a static variable called $connected, which is used as a flag to connect to MySQL only once. Even though this variable is brought to life within this specific method, its scope is still class-level, meaning that it behaves exactly as if it was a declared static class property. On the other hand, the source code of the "MySQLi_ResultWrapper" class remains entirely unchanged, but for the sake of completeness, I included its definition below once again: class MySQLi_ResultWrapper extends MySQLi_Result implements Iterator, Countable { private $_pointer = 0;
// fetch row as an object public function fetchObject() { if (!$row = $this->fetch_object()) { return NULL; } return $row; }
// fetch row as an associative array public function fetchAssocArray() { if (!$row = $this->fetch_assoc()) { return NULL; } return $row; }
// fetch row as an enumerated array public function fetchNumArray() { if (!$row = $this->fetch_row()) { return NULL; } return $row; }
// fetch all rows public function fetchAll($type = MYSQLI_ASSOC) { if ($type !== MYSQLI_ASSOC AND $type !== MYSQLI_NUM AND $type !== MYSQLI_BOTH) { $type = MYSQLI_ASSOC; } if (!$rows = $this->fetch_all($type)) { return NULL; } return $rows; }
// get definition information on fields public function fetchFieldsInfo() { if (!$fieldsInfo = $this->fetch_fields()) { throw new Exception('No information available for table fields.'); } return $fieldsInfo; }
// get definition information on next field public function fetchFieldInfo() { if (!$fieldInfo = $this->fetch_field()) { throw new Exception('No information available for current table field.'); } return $fieldInfo; }
// move pointer in result set to specified offset public function movePointer($offset) { $offset = abs((int)$offset); $limit = $this->num_rows - 1; if ($limit <= 0 OR $offset > $limit) { return FALSE; } unset($limit); return $this->data_seek($offset); }
// count rows in result set (implementation required by 'count()' method in Countable interface) public function count() { return $this->num_rows; }
// reset result set pointer (implementation required by 'rewind()' method in Iterator interface) public function rewind() { $this->_pointer = 0; $this->movePointer($this->_pointer); return $this; }
// get current row set in result set (implementation required by 'current()' method in Iterator interface) public function current() { if (!$this->valid()) { throw new Exception('Unable to retrieve current row.'); } $this->movePointer($this->_pointer); return $this->fetchObject(); }
// get current result set pointer (implementation required by 'key()' method in Iterator interface) public function key() { return $this->_pointer; }
// move forward result set pointer (implementation required by 'next()' method in Iterator interface) public function next() { ++$this->_pointer; $this->movePointer($this->_pointer); return $this; }
// determine if result set pointer is valid or not (implementation required by 'valid()' method in Iterator interface) public function valid() { return $this->_pointer < $this->num_rows; }
// free up result set public function __destruct() { $this->close(); } } At this point, the "MySQLiWrapper" class internally uses a static variable created within its "connect()" method to avoid connecting to MySQL each time it performs a query. Obviously, this is the expected and desired behavior of the class, but to demonstrate that it really works this way, in the following section I'm going to build a script that will show how to use the modified version of this sample MySQL driver. Read the next segment. We're almost finished.
blog comments powered by Disqus |
|
|
|
|
|
|
|