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