Content · Programming · PHP

Mapping Database Rows to Typed PHP Objects

Convert database rows into explicit typed domain objects after validation and normalization. PDO often returns numeric values as strings depending on driver and options; cast and validate intentionally.

1 views Published Oct 17, 2026 Updated Oct 17, 2026 Know-Stuff

Convert database rows into explicit typed domain objects after validation and normalization.

The examples focus on the operation itself, including the important distinction: FETCH_ASSOC returns raw columns; DTO construction enforces application types.

What It Does


Use the examples below to observe the behavior on a small dataset before extending it to application code.

Before You Start


The examples use PHP 8.2+ features where shown. Database snippets require the corresponding PDO driver, demo tables, and credentials configured outside source code.

Example 1: Basic Use


Cast DB driver values deliberately and validate domain constraints when constructing typed objects.

<?php
final readonly class UserView {
    public function __construct(public int $id, public string $email) {}
    public static function fromRow(array $row): self {
        return new self((int) $row["id"], (string) $row["email"]);
    }
}
$pdo = new PDO(
    "mysql:host=" . (getenv("DB_HOST") ?: "127.0.0.1") . ";dbname=" . (getenv("DB_NAME") ?: "demo") . ";charset=utf8mb4",
    getenv("DB_USER") ?: "app",
    getenv("DB_PASSWORD") ?: "",
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false]
);
$row = $pdo->query("SELECT id, email FROM users ORDER BY id LIMIT 1")->fetch(PDO::FETCH_ASSOC);
if ($row) { $user = UserView::fromRow($row); echo $user->email; }

This example is meant for a configured application environment; output depends on the installed extension, external service, or database contents.

Example 2: Checking Behavior


Cast DB driver values deliberately and validate domain constraints when constructing typed objects. The typed mapping is independent of the SQL row selection.

<?php
final readonly class UserView {
    public function __construct(public int $id, public string $email) {}
    public static function fromRow(array $row): self {
        return new self((int) $row["id"], (string) $row["email"]);
    }
}
$pdo = new PDO(
    "mysql:host=" . (getenv("DB_HOST") ?: "127.0.0.1") . ";dbname=" . (getenv("DB_NAME") ?: "demo") . ";charset=utf8mb4",
    getenv("DB_USER") ?: "app",
    getenv("DB_PASSWORD") ?: "",
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false]
);
$row = $pdo->query("SELECT id, email FROM users ORDER BY id DESC LIMIT 1")->fetch(PDO::FETCH_ASSOC);
if ($row) { $user = UserView::fromRow($row); echo $user->email; }

This example is meant for a configured application environment; output depends on the installed extension, external service, or database contents.

Example 3: Practical Example


Cast DB driver values deliberately and validate domain constraints when constructing typed objects. The typed mapping is independent of the SQL row selection.

<?php
final readonly class UserView {
    public function __construct(public int $id, public string $email) {}
    public static function fromRow(array $row): self {
        return new self((int) $row["id"], (string) $row["email"]);
    }
}
$pdo = new PDO(
    "mysql:host=" . (getenv("DB_HOST") ?: "127.0.0.1") . ";dbname=" . (getenv("DB_NAME") ?: "demo") . ";charset=utf8mb4",
    getenv("DB_USER") ?: "app",
    getenv("DB_PASSWORD") ?: "",
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false]
);
$row = $pdo->query("SELECT id, email FROM users WHERE active = 1 ORDER BY id LIMIT 1")->fetch(PDO::FETCH_ASSOC);
if ($row) { $user = UserView::fromRow($row); echo $user->email; }

This example is meant for a configured application environment; output depends on the installed extension, external service, or database contents.

Important Behavior and Edge Cases


PDO often returns numeric values as strings depending on driver and options; cast and validate intentionally.

Comparison with Related Approaches


ApproachDifference
Mapping Database Rows to Typed PHP ObjectsConvert database rows into explicit typed domain objects after validation and normalization.
Related API or alternativeFETCH_ASSOC returns raw columns; DTO construction enforces application types.

Common Beginner Mistakes


MistakeCorrect approach
Ignoring the operation-specific limitsPDO often returns numeric values as strings depending on driver and options; cast and validate intentionally.
Confusing it with a related APIFETCH_ASSOC returns raw columns; DTO construction enforces application types.

Key Takeaways


  • Convert database rows into explicit typed domain objects after validation and normalization.
  • PDO often returns numeric values as strings depending on driver and options; cast and validate intentionally.
  • FETCH_ASSOC returns raw columns; DTO construction enforces application types.

Use Mapping Database Rows to Typed PHP Objects when its documented behavior matches the problem. Test the relevant edge cases in your own runtime before deploying it.

Share this resourceSend this page to someone who may find it useful.