在使用PHP 的PDO 操作數據庫時, PDOStatement::fetchObject是一個非常實用的方法。它可以將一條記錄以對象的形式返回,並將每一列的值賦給對象的屬性。然而,當數據庫列的類型與目標對象屬性的期望類型不一致時,可能會出現一些令人困惑的問題,比如類型不匹配、隱式轉換錯誤或行為異常。
class User {
public int $id;
public string $name;
public bool $is_active;
}
$stmt = $pdo->query('SELECT id, name, is_active FROM users');
$user = $stmt->fetchObject('User');
假設users表中is_active列是一個TINYINT(1)類型,而在User類中我們定義的是bool類型。如果is_active的值是1或0 ,你可能期望它被自動轉換成true或false 。但實際中,PHP 會直接賦予int類型的值,這會導致類型不一致,甚至在嚴格類型模式下直接拋出錯誤。
fetchObject內部是通過__set()或直接賦值的方式來將數據庫字段映射到對象屬性上的。它並不進行類型轉換,而是按照數據庫原始值進行直接賦值。這就意味著:
數據庫中的INT值會變成PHP 的int
VARCHAR會變成string
TINYINT(1)雖然常用於布爾值,但實際是整數類型
在開啟declare(strict_types=1)或PHP 8.2+ 的類型提示加強後,類型不匹配會造成運行時錯誤。
一種穩妥的做法是在獲取對像後,手動轉換每個字段到合適的類型。這種方式最安全,也最具可讀性。
$user = $stmt->fetchObject('User');
if ($user !== false) {
$user->id = (int)$user->id;
$user->name = (string)$user->name;
$user->is_active = (bool)$user->is_active;
}
fetchObject支持傳入構造函數參數。如果你設計了一個接受初始化數據的構造函數,可以優雅地實現類型轉換:
class User {
public function __construct(
public int $id,
public string $name,
public bool $is_active
) {}
}
$stmt = $pdo->query('SELECT id, name, is_active FROM users');
$user = $stmt->fetchObject('User');
但這裡的問題是:如果數據庫列順序不一致或者字段未完全匹配,可能會拋出異常。
如果數據量大或者對象結構複雜,可以考慮使用一個工廠類來處理轉換邏輯。
class UserFactory {
public static function fromDb(stdClass $row): User {
return new User(
(int)$row->id,
(string)$row->name,
(bool)$row->is_active
);
}
}
$stmt = $pdo->query('SELECT id, name, is_active FROM users');
$row = $stmt->fetchObject();
if ($row !== false) {
$user = UserFactory::fromDb($row);
}
這樣做雖然多了些代碼,但結構清晰,邏輯集中,便於單元測試和維護。
你還可以使用PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE模式,但同樣需要留意類型轉換的問題。 PHP 不會在內部進行類型推斷。
$stmt = $pdo->query('SELECT id, name, is_active FROM users');
$stmt->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'User');
$user = $stmt->fetch();
如上,雖然代碼精簡,但仍然不能解決類型強制的問題。
當使用PDOStatement::fetchObject進行對象化提取時,務必注意數據庫字段類型和對象屬性類型之間的對應關係。 PHP 並不會自動進行智能轉換,尤其在開啟類型提示後,更需要開發者顯式地處理轉換邏輯。最推薦的方式是將數據提取和對象構造解耦,例如使用工廠類或手動轉換,從而提升代碼的健壯性和可維護性。
更多相關例子可以參考: https://gitbox.net/pdo/fetchobject-type-conversion