在使用PDO 進行數據庫操作時, PDOStatement::fetchObject是一個非常方便的方法,可以直接將查詢結果映射為一個對象。但有時候我們會遇到類型不匹配的問題,比如原本在數據庫裡是整型( int )的字段,結果卻被轉成了字符串( string )。這種情況在處理大量數據或需要嚴格類型的數據結構時,尤其麻煩。
下面我們來看看原因,以及解決方法。
PDOStatement::fetchObject本身不會根據數據庫字段的類型去自動推斷PHP 的類型。它只是簡單地把數據填充到對象屬性中,所以很多時候,數字會被當作字符串處理。這是因為PDO 默認以字符串形式返回所有數據。
來看一個例子:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$stmt = $pdo->query('SELECT id, name FROM users');
$user = $stmt->fetchObject();
var_dump($user);
?>
輸出可能是:
object(stdClass)#1 (2) {
["id"]=>
string(1) "1"
["name"]=>
string(4) "John"
}
可以看到,即使id在數據庫中是INT類型,結果在PHP 中卻是string 。
要解決這個問題,有幾種常用方法:
PDO 有一個設置叫做PDO::ATTR_STRINGIFY_FETCHES ,可以控制是否將數字自動轉換成字符串。但是需要注意的是,這個選項只能在fetch() 系列函數中生效,對fetchObject沒有直接作用,所以不推薦。
最實際的方法是:定義一個類,並且在構造函數或者魔術方法__set中,手動進行類型轉換。
比如:
<?php
class User {
public int $id;
public string $name;
public function __construct() {
// 可以在這裡進行類型強制
}
public function __set($name, $value) {
if ($name === 'id') {
$this->id = (int) $value;
} elseif ($name === 'name') {
$this->name = (string) $value;
}
}
}
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$stmt = $pdo->query('SELECT id, name FROM users');
$user = $stmt->fetchObject(User::class);
var_dump($user);
?>
這樣,當你從數據庫取數據時,就可以確保類型正確。
在SQL 語句裡,直接把字段強製成需要的類型,比如:
SELECT id + 0 AS id, name FROM users
這樣id在數據庫返回時就已經是整數了,但這種方法不是特別優雅,並且可維護性差,所以只適合臨時救急。
如果你的項目中有很多地方都需要對象映射,可以考慮寫一個通用的Mapper 工具。例如:
<?php
function mapUser($data) {
$user = new User();
$user->id = (int) $data->id;
$user->name = (string) $data->name;
return $user;
}
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$stmt = $pdo->query('SELECT id, name FROM users');
$rawUser = $stmt->fetchObject();
$user = mapUser($rawUser);
var_dump($user);
?>
這種方法可控性更好,便於統一管理和擴展,比如後期加上驗證邏輯。
數據表字段類型設計合理:盡量讓數據庫表的字段定義清晰,例如id 一定是INT ,金額一定是DECIMAL ,不要用字符串代替數字字段。
使用強類型聲明:在PHP 7.4+ 中,利用類型提示(Type Hinting)和屬性類型聲明,可以更早發現錯誤。
統一的數據訪問層(DAL)封裝:如果項目規模較大,最好將數據庫訪問和對象映射封裝成統一模塊,避免重複勞動。
使用fetchObject是很方便,但為了保證數據類型正確,通常推薦自己定義類,並配合手動轉換,或者使用映射函數。這樣可以讓代碼更健壯,減少後續調試麻煩。
如果你希望了解更詳細的PDO 用法和對象映射,可以參考: https://gitbox.net/docs/pdo-tutorial 。