Working with Results
Every query that reads rows returns result objects: collections you can loop
like arrays, and values that HTML-encode themselves on output. (insert(),
update(), and delete() return plain ints.) This page covers the result
hierarchy, output encoding, and the methods available at each level.
The Result Hierarchy
Section titled “The Result Hierarchy”Query → Result (SmartArrayHtml) → Rows (SmartArrayHtml) → Values (SmartString)$users = DB::select('users'); // result - collection of rowsforeach ($users as $user) { // row - one record echo $user->name; // value - HTML-encodes itself}Output Encoding
Section titled “Output Encoding”Values HTML-encode themselves in string context, so echo, print, and
string interpolation are XSS-safe with no extra effort. For other contexts,
ask for the encoding you need.
| Expression | Result |
|---|---|
$user->name | HTML-encoded (string context) |
$user->name->value() | Original raw value and type |
$user->name->rawHtml() | Unencoded, for HTML you trust (alias of value()) |
$user->name->urlEncode() | URL-encoded |
$user->name->jsonEncode() | JSON-encoded |
// HTML context - encodes automaticallyecho "<p>$user->name</p>";
// URL parameterecho "<a href='/profile?name={$user->name->urlEncode()}'>Profile</a>";
// JavaScriptecho "<script>let name = {$user->name->jsonEncode()};</script>";
// Logic - compare the raw value, not the encoded stringif ($user->isAdmin->value()) { echo "Admin";}rawHtml() is the one output path that skips encoding. Call it only on HTML
you control and trust; Security Gotchas covers why it’s
the single name for unencoded output.
Getting Values from a Row
Section titled “Getting Values from a Row”Access columns with object notation. For a column that may be empty, chain
or() for a fallback:
echo $user->name;echo $user->nickname->or('Anonymous'); // fallback when null or ''Getting Raw Data
Section titled “Getting Raw Data”value() returns one field’s original value and type; toArray() converts a
row or a whole result to plain PHP arrays:
$user = DB::selectOne('users', ['id' => 1]);$name = $user->name->value(); // "O'Brien & Sons" - exactly as stored$data = $user->toArray(); // ['id' => 1, 'name' => "O'Brien & Sons", ...]
$rows = DB::select('users')->toArray(); // array of plain row arraysChaining Value Methods
Section titled “Chaining Value Methods”Value methods return a new SmartString, so transformations chain:
// Strip HTML tags, then shorten to 100 characters with an ellipsisecho $article->body->textOnly()->maxChars(100);
// Format a number and prepend a currency symbol (a blank price stays blank, no stray $)echo $product->price->numberFormat(2)->prepend('$'); // $1,234.56
// Format a date; supports years 1000-9999, anything else// (null, invalid, zero dates like 0000-00-00) falls through to the or()echo $user->lastLogin->dateFormat('M j, Y')->or('Never');Debugging with print_r()
Section titled “Debugging with print_r()”The result objects describe themselves when inspected; print_r() shows the
data, and ->debug() adds the executed SQL and MySQL metadata:
print_r($users); // rows and valuesprint_r($user); // one row's columns and valuesprint_r($user->name); // one value's raw data
$users->debug(); // the executed SQL, rows, and MySQL metadataCMS Builder users: showme() does the same thing as print_r(), wrapped in
<xmp> tags for readable browser output.
Query Metadata - mysqli()
Section titled “Query Metadata - mysqli()”Results carry their MySQL metadata, most useful with DB::query().
| Method | Returns |
|---|---|
$result->mysqli('insert_id') | Auto-increment ID from an INSERT |
$result->mysqli('affected_rows') | Rows changed by INSERT/UPDATE/DELETE |
$result->mysqli('query') | The executed SQL |
$result->mysqli() | All metadata as an array |
$result = DB::query("INSERT INTO ::users SET name = ?", 'Alice');$newId = $result->mysqli('insert_id');That’s for inserts written as raw SQL; DB::insert() returns the new ID
directly, no metadata call needed.
Result Methods (Collections)
Section titled “Result Methods (Collections)”The most used methods on the collection returned by DB::select() and
DB::query(). This isn’t the full list; see
SmartArray for
everything.
| Method | Description |
|---|---|
count($result) | Number of rows ($result->count() works too) |
$result->first() | First row (SmartNull when the result is empty; chaining still works) |
$result->toArray() | Plain array of raw row arrays |
$result->column('col') | One column as a new collection |
$result->sortBy('col') | Sort rows by column |
$result->filter(fn) | Keep rows where the callback returns true |
$result->where('col', $val) | Keep rows where the column matches a value |
$result->map(fn) | Transform each row |
$result->indexBy('col') | Lookup array keyed by column |
$result->groupBy('col') | Groups of rows keyed by column value |
use Itools\SmartString\SmartString;
$users = DB::select('users', ['status' => 'active']);
echo count($users) . " active users";
// One column$names = $users->column('name'); // collection: ['Alice', 'Bob', 'Charlie', ...]
// Lookup by primary key - the ->{'...'} syntax reads keys plain property syntax can't, like numbers$byId = $users->indexBy('id');echo $byId->{'42'}->name;
// Group rows by a column value$byCity = $users->groupBy('city');foreach ($byCity as $city => $cityUsers) { $city = SmartString::new($city); // foreach keys come back plain; this makes them encode like fields echo "<h2>$city (" . count($cityUsers) . ")</h2>";}Row Methods
Section titled “Row Methods”Each row in a collection, and the return value of DB::selectOne().
| Method | Description |
|---|---|
$row->columnName | Column value as SmartString |
$row->{'users.name'} | Column whose key plain syntax can’t type: Smart Join keys, numeric indexes |
$row->keys() | Column names |
$row->values() | Column values |
$row->toArray() | Raw associative array |
$row->isEmpty() | True when no row was found |
Value Methods (SmartString)
Section titled “Value Methods (SmartString)”Each column value is a SmartString. These are the most used methods.
Text
| Method | Description |
|---|---|
->textOnly() | Remove HTML tags, decode entities, trim |
->maxChars(100) | Shorten to N characters with ellipsis |
->maxWords(20) | Shorten to N words with ellipsis |
->nl2br() | HTML-encode, then newlines to <br> (returns a plain string) |
->trim() | Trim whitespace |
Formatting
| Method | Description |
|---|---|
->dateFormat('M j, Y') | Format a date: “Sep 10, 2026” |
->numberFormat(2) | Format a number: “1,234.56” |
->int(), ->float() | Convert to a plain PHP type |
Conditional fallbacks
| Method | Applies when |
|---|---|
->or('N/A') | Value is null or '' (zero stays) |
->ifNull('N/A') | Value is null |
->ifZero('Free') | Value is numeric zero |
->append(' items') | Appends when value is present (including zero) |
->prepend('$') | Prepends when value is present (including zero) |
Full References
Section titled “Full References”These objects come from ZenDB’s companion libraries, and the complete method lists live in their own docs:
- SmartArray - results and rows
- SmartString - values