In case you don’t know, the native Iterator interface declares five methods called “rewind(),” “current(),” “key(),” “valid()” and “next().” This implies, obviously, that any class implementing the interface must give a concrete implementation to each of these methods. In the case of the previous “MySQLi_ResultWrapper” class, turning it into an implementer of Iterator will make it possible to traverse database result sets using a “foreach” loop, as if they were plain arrays. Now, it’s time to refactor the class in question, so it can partially implement the methods declared by Iterator. After the corresponding refactoring process, the “MySQLi_ResultWrapper” class will have the following definition: class MySQLi_ResultWrapper extends MySQLi_Result implements Iterator { 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 NULL; } unset($limit); return $this->data_seek($offset); }
// 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(); }
// free up result set public function __destruct() { $this->close(); } } Definitely, the above “MySQLi_ResultWrapper” class is starting to take shape. It's now an implementer of the Iterator interface, and in consequence it must implement all of its declared methods. For the moment, the class only does this with the “rewind()” and “current()” inherited methods, which internally use another one called “movePointer()” in order to reset the pointer of a given result set and get its current element. Naturally, if you give the class a try in its current state, you’ll get a loud complaint from the PHP engine, since it doesn’t implement all of the methods of Iterator. However, this is a work in progress; the remaining methods will be properly defined in the upcoming tutorial. Final thoughts In this first chapter of the series, I introduced you to using the Iterator, Countable and ArrayAccess interfaces that come packaged with the Standard PHP Library. This part showed how to implement only some of the methods declared by the Iterator interface within a class that manipulates MySQL result sets via an intuitive API. In the next installment, things will get more interesting. I’m going to finish building this class by giving a concrete implementation to the Iterator’s remaining methods. Here’s my final piece of advice: don’t miss the next part!
blog comments powered by Disqus |
|
|
|
|
|
|
|