Merge "Use gendered pronouns in emailuserfooter"
[mediawiki.git] / includes / libs / rdbms / database / resultwrapper / ResultWrapper.php
blob94ce8e93010eb8ba96bbf854c8a1fa5442cc7028
1 <?php
3 namespace Wikimedia\Rdbms;
5 use OutOfBoundsException;
6 use stdClass;
8 /**
9 * Result wrapper for grabbing data queried from an IDatabase object
11 * Only IDatabase-related classes should construct these. Other code may
12 * use the FakeResultWrapper class for convenience or compatibility shims.
14 * Note that using the Iterator methods in combination with the non-Iterator
15 * IDatabase result iteration functions may cause rows to be skipped or repeated.
17 * By default, this will use the iteration methods of the IDatabase handle if provided.
18 * Subclasses can override methods to make it solely work on the result resource instead.
20 * @ingroup Database
22 abstract class ResultWrapper implements IResultWrapper {
23 /**
24 * @var int The offset of the row that would be returned by the next call
25 * to fetchObject().
27 protected $nextPos = 0;
29 /**
30 * @var int The offset of the current row that would be returned by current()
31 * and may have been previously returned by fetchObject().
33 protected $currentPos = 0;
35 /**
36 * @var stdClass|array|bool|null The row at $this->currentPos, or null if it has
37 * not yet been retrieved, or false if the current row was past the end.
39 protected $currentRow;
41 /**
42 * @var string[]|null Cache of field names
44 private $fieldNames;
46 /**
47 * Get the number of rows in the result set
49 * @since 1.37
50 * @return int
52 abstract protected function doNumRows();
54 /**
55 * Get the next row as a stdClass object, or false if iteration has
56 * proceeded past the end. The offset within the result set is in
57 * $this->currentPos.
59 * @since 1.37
60 * @return stdClass|bool
62 abstract protected function doFetchObject();
64 /**
65 * Get the next row as an array containing the data duplicated, once with
66 * string keys and once with numeric keys, per the PDO::FETCH_BOTH
67 * convention. Or false if iteration has proceeded past the end.
69 * @return array|bool
71 abstract protected function doFetchRow();
73 /**
74 * Modify the current cursor position to the row with the specified offset.
75 * If $pos is out of bounds, the behaviour is undefined.
77 * @param int $pos
79 abstract protected function doSeek( $pos );
81 /**
82 * Free underlying data. It is not necessary to do anything.
84 abstract protected function doFree();
86 /**
87 * Get the field names in the result set.
89 * @return string[]
91 abstract protected function doGetFieldNames();
93 public function numRows() {
94 return $this->doNumRows();
97 public function count(): int {
98 return $this->doNumRows();
101 public function fetchObject() {
102 $this->currentPos = $this->nextPos++;
103 $this->currentRow = $this->doFetchObject();
104 return $this->currentRow;
107 public function fetchRow() {
108 $this->currentPos = $this->nextPos++;
109 $this->currentRow = $this->doFetchRow();
110 return $this->currentRow;
113 public function seek( $pos ): void {
114 $numRows = $this->numRows();
115 // Allow seeking to zero if there are no results
116 $max = $numRows ? $numRows - 1 : 0;
117 if ( $pos < 0 || $pos > $max ) {
118 throw new OutOfBoundsException( __METHOD__ . ': invalid position' );
120 if ( $numRows ) {
121 $this->doSeek( $pos );
123 $this->nextPos = $pos;
124 $this->currentPos = $pos;
125 $this->currentRow = null;
128 public function free() {
129 $this->doFree();
130 $this->currentRow = false;
133 public function rewind(): void {
134 $this->seek( 0 );
137 #[\ReturnTypeWillChange]
138 public function current() {
139 $this->currentRow ??= $this->fetchObject();
141 return $this->currentRow;
144 public function key(): int {
145 return $this->currentPos;
148 public function next(): void {
149 $this->fetchObject();
152 public function valid(): bool {
153 return $this->currentPos >= 0
154 && $this->currentPos < $this->numRows();
157 public function getFieldNames() {
158 $this->fieldNames ??= $this->doGetFieldNames();
159 return $this->fieldNames;