RecordSets¶
Calling query()
on a driver or prepared statement will return a recordset.
The data can be fetched row-by-row via an iterator or all at once as an array.
Each row of the recordset can only be traversed one time, and must be done in
order.
Naming conventions¶
There are many different methods associated with the recordset, depending on how you want the data returned (associative array, indexed array, etc) and if you want an array or an iterator.
The methods are named after the following conventions:
fetch
returns data. When combined withAll
,Column
, orKeyed
, it will return the remainder of the resultset as an array. Otherwise, it is only returning something from the next row.get*Iterator
returns an iterator that returns one row at a time. This is the best way to get data if you simply need to process records.- The “default” row type is an associative array.
- The methods with an explicit
Array
return an indexed array. - The “keyed” methods return some sort of associative array where the key comes from data in the column.
All of the methods are listed below, followed by an overview of the main differences between them. Then the keyed methods and callbacks are covered in more detail.
Fetching one record¶
Type | Row Type | Method |
---|---|---|
return by value | one value from single row | fetchValue($i = 0) : string |
return by value | associative array | fetchRow() : array |
return by value | indexed array | fetchRowAsArray() : array |
modify by reference | associative array | fetchRowInto(&$array) : boolean |
modify by reference | indexed array | fetchRowIntoArray(&$array) : boolean |
modify by reference | object | fetchRowIntoObject(&object) : boolean |
Fetching multiple records¶
Key | Row Type | Method |
---|---|---|
indexed | associative array | fetchAll() : array |
indexed | indexed array | fetchAllAsArray() : array |
indexed | callback | fetchAllWithCallback($cb) : array |
indexed | scalar | fetchColumn($i = 0) : array |
associative | associative array | fetchKeyed($key = '') : array |
associative | indexed array | fetchKeyedAsArray($i = 0) : array |
associative | callback | fetchKeyedWithCallback($cb, $key = '') : array |
Iterators¶
Key | Row Type | Method |
---|---|---|
indexed | associative array | getIterator() : iterator |
indexed | indexed array | getArrayIterator() : iterator |
indexed | callback | getCallbackIterator($cb) : iterator |
indexed | scalar | getColumnIterator($i = 0) : iterator |
associative | associative array | getKeyedIterator($key = '') : iterator |
associative | indexed array | getKeyedArrayIterator($i = 0) : iterator |
associative | callback | getKeyedCallbackIterator($cb, $key = '') : iterator |
Fetching data¶
The most direct way to fetch data is via the default iterator:
foreach ($driver->query($sql) as $row)
{
echo $row['columnName'], PHP_EOL;
}
This is equivalent to:
foreach ($driver->query($sql)->getIterator() as $row) ...
Single value¶
If you only need a single value from a row, you can use fetchValue()
.
$value = $driver->query('SELECT COUNT(*) FROM t1')->fetchValue();
It defaults to using the first column, but you can specifiy a different column by passing the index (not the name of column). But whenever possible, it’s better to just rewrite the SQL to only return the column you are interested in.
Single row¶
If you only need a single row, then you can use fetchRow()
or
fetchRowAsArray()
.
$row = $driver->query($sql)->fetchRow();
echo $row['columnName'], PHP_EOL;
$row = $driver->query($sql)->fetchRowAsArray();
echo $row[0], PHP_EOL;
Note
Of course, these fetch value and row methods can be used multiple times on the same recordset. But usually it’s much more succinct to use the related iterator or fetchAll/Column methods.
Fetching by reference¶
It’s also possible to fetch into an array or object. These methods return
true
(more records) or false
(no more records).
$rs = $driver->query($sql);
while ($rs->fetchInto($row))
{
echo $row['columnName'], PHP_EOL;
}
This is the only way to fetch into an object (other than by custom callbacks):
$rs = $driver->query($sql);
$object = new stdClass;
while ($rs->fetchIntoObject($object))
{
echo $object->columName, PHP_EOL;
}
In both cases, the supplied array or object will have its elements or properties overridden. Anything that does not exist in the row will not be modified.
The entire recordset¶
The fetchAll/Column/Keyed methods return the entire recordset (or more accurately the remainder of the recordset) as an array. This is useful when you need the data as an array, so that you can perform arbitrary lookups or iterate through it multiple times.
$results = $driver->query($sql)->fetchAll();
Note
It’s possible to mix things together:
$q = $driver->query($sql);
$firstRow = $q->fetchRow();
$remainingRows = $q->fetchAll();
The data will not be duplicated, as you can only iterate over each row one time.
Iterators¶
The iterators allow you to iterate over the recordset with the format that best
suits your needs. When iterating directly over the recordset, you are using the
getIterator()
method implicitly.
To use indexed arrays:
foreach ($driver->query($sql)->getArrayIterator() as $row)
{
echo $row[0], PHP_EOL;
}
To iterate over the nth column:
foreach ($driver->query($sql)->getColumnIterator() as $value)
{
echo $value, PHP_EOL;
}
Keyed arrays¶
All of the keyed
methods allow you to specify a column to use as the key, as
opposed to a zero-based array. Imagine a dataset that looks like:
n | en | sp |
---|---|---|
1 | one | uno |
2 | two | dos |
With SELECT *
and fetchAll
, you would get an array just like that:
$driver->query('SELECT * FROM t1')->fetchAll()
[
0 => ['n' => '1', 'en' => 'one', 'sp' => 'uno'],
1 => ['n' => '2', 'en' => 'two', 'sp' => 'dos']
]
But say you want the n to be the key of the array. In that case, you need to use one of the keyed methods.
$driver->query('SELECT * FROM t1')->fetchKeyed()
[
1 => ['en' => 'one', 'sp' => 'uno'],
2 => ['en' => 'two', 'sp' => 'dos']
]
The keyed value is removed from the row. If there is only one value left, then a simple key => value array is returned.
$driver->query('SELECT n,en FROM t1')->fetchKeyed()
[
1 => 'one',
2 => 'two'
]
If there are no more columns left, then the true
is used for the value.
$driver->query('SELECT en FROM t1')->fetchKeyed()
[
'one' => true,
'two' => true
]
The keyed iterator works the same way:
foreach ($driver->query('SELECT n,en')->getKeyedIterator() as $n => $en)
{
echo $n, ': ', $en, PHP_EOL;
}
Callbacks¶
For more flexibility in how the records are returned, use a callback. Note that there is no way to directly return an object. This introduces complexities (constructor parameters, injecting dependencies, etc) that are better handled by a callback.
Callbacks always receive the entire row as an associative array. They are free to return anything.
The following illustrates using a callback to handle custom object creation:
$cb = function (array $row) {
$myObject = new MyObject;
$myObject->setFirstName($row['first_name']);
$myObject->setLastName($row['last_name']);
return $myObject;
};
foreach ($driver->query($sql)->getCallbackIterator($cb) as $myObject)
{
echo $myObject->getFirstName(), PHP_EOL;
}
Or to retrieve them all in an array:
$myObjects = $driver->query($sql)->fetchAllWithCallback($cb);
Note
There is no single row callback because you could just as easily do this:
$myObject = $cb($driver->query($sql)->fetchRow());
Keyed callbacks¶
Callbacks can also be used with keyed queries. As with regular queries, those callbacks retreive the entire row as an associative array. However, keyed callbacks return an array with the key and value.