In PHP development, we often use the mysqli extension to interact with the MySQL database, especially when we perform query operations, we usually get a mysqli_result object. However, the mysqli_result object itself does not support direct use of foreach to traverse query results like arrays or other iterable objects, which makes it possible that we need to manually call fetch_assoc() or other similar functions to get each row of data when processing query results.
In order to more conveniently process query results, we can encapsulate mysqli_result into an iterable object, making it more concise and intuitive when processing query results. Next, we will explore how to achieve this.
We can create a class to implement the Iterator interface so that we can encapsulate mysqli_result as an iterable object. First, we need to make sure that the class can receive a mysqli_result object and make it support iteration by implementing the interface method.
<?php
class MysqliResultIterator implements Iterator {
private $result;
private $currentRow;
private $currentIndex;
public function __construct($mysqliResult) {
$this->result = $mysqliResult;
$this->currentIndex = 0;
}
public function rewind() {
$this->currentIndex = 0;
$this->currentRow = $this->result->fetch_assoc();
}
public function current() {
return $this->currentRow;
}
public function key() {
return $this->currentIndex;
}
public function next() {
$this->currentRow = $this->result->fetch_assoc();
$this->currentIndex++;
}
public function valid() {
return $this->currentRow !== null;
}
}
?>
In this class, we implement five methods of the Iterator interface:
rewind() : Reset the iterator to the first element.
current() : Returns the current element.
key() : Returns the index of the current element.
next() : Move to the next element.
valid() : Check whether the current element is valid.
Through these methods, the MysqliResultIterator class allows us to directly traverse the query results like operating arrays or other iterable objects.
Once we have defined this iterator class, we can create an iterable object by passing the mysqli_result object to the MysqliResultIterator class.
<?php
// Suppose you have established a database connection and executed a query
$mysqli = new mysqli("localhost", "username", "password", "database");
$query = "SELECT id, name, email FROM users";
$result = $mysqli->query($query);
if ($result) {
// Create a MysqliResultIterator Object
$iterator = new MysqliResultIterator($result);
// pass foreach Iterative query results
foreach ($iterator as $index => $row) {
echo "Index: " . $index . "<br>";
echo "ID: " . $row['id'] . "<br>";
echo "Name: " . $row['name'] . "<br>";
echo "Email: " . $row['email'] . "<br><hr>";
}
// Close the query result
$result->free();
} else {
echo "Query failed: " . $mysqli->error;
}
$mysqli->close();
?>
In the above code, we create a MysqliResultIterator object and iterate through the foreach statement to query the result. You will find that using this iterator, the code becomes more concise, avoiding the manual call to the fetch_assoc() method.
If you need more flexible features such as supporting multiple data formats (association arrays, numeric arrays, etc.), you can further expand the iterator to support more options. For example, add a parameter to specify whether to return data in the form of an associative array or array of numbers.
<?php
class MysqliResultIterator implements Iterator {
private $result;
private $currentRow;
private $currentIndex;
private $fetchType;
public function __construct($mysqliResult, $fetchType = MYSQLI_ASSOC) {
$this->result = $mysqliResult;
$this->currentIndex = 0;
$this->fetchType = $fetchType;
}
public function rewind() {
$this->currentIndex = 0;
$this->currentRow = $this->result->fetch_array($this->fetchType);
}
public function current() {
return $this->currentRow;
}
public function key() {
return $this->currentIndex;
}
public function next() {
$this->currentRow = $this->result->fetch_array($this->fetchType);
$this->currentIndex++;
}
public function valid() {
return $this->currentRow !== null;
}
}
?>
With this improvement, you can specify the format of the query result when creating an iterator, such as using MYSQLI_ASSOC or MYSQLI_NUM to return an associative array or a numeric array.
By encapsulating mysqli_result into an object that implements the Iterator interface, we can make the processing of database query results more convenient and elegant. This not only makes the code concise, but also provides more flexibility and can better handle different types of query results.
This encapsulation method can greatly improve the maintainability and readability of the code, especially in scenarios where large amounts of data are required.