在使用PDO 進行數據庫操作時, PDOStatement::fetchObject是一個非常方便的方法,它可以直接將查詢結果的一行數據映射為一個對象。不過,默認情況下,如果數據庫返回的是帶有下劃線或者不同風格命名的字段,直接用fetchObject可能不會把這些字段正確地映射到對象的屬性上。本文將詳細講解如何優雅地處理這種情況。
假設你的數據庫表users中有如下字段:
id
user_name
email_address
一般我們可以這樣查詢:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'root', 'password');
$stmt = $pdo->query('SELECT id, user_name, email_address FROM users WHERE id = 1');
$user = $stmt->fetchObject();
echo $user->id; // 正常輸出
echo $user->user_name; // 正常輸出
echo $user->email_address; // 正常輸出
?>
這裡一切看起來都很順利。但如果你的實體類(比如User )使用的是駝峰命名,比如userName和emailAddress ,那麼直接使用fetchObject('User')將不會正確賦值。
因為fetchObject默認是按照數據庫返回的列名直接賦值到對象屬性的。數據庫中字段是下劃線風格( user_name ),而對像中是駝峰風格( userName ),自然對應不上。
比如下面的User類:
<?php
class User {
public int $id;
public string $userName;
public string $emailAddress;
}
?>
直接用$stmt->fetchObject('User') , userName和emailAddress是拿不到值的。
最簡單粗暴的做法,就是在SQL 查詢時,把字段起個符合對象屬性名的別名:
<?php
$stmt = $pdo->query('
SELECT
id,
user_name AS userName,
email_address AS emailAddress
FROM users
WHERE id = 1
');
$user = $stmt->fetchObject('User');
echo $user->userName; // 正確輸出
echo $user->emailAddress; // 正確輸出
?>
這種方法簡單直接,無需修改實體類。但如果查詢字段多、表複雜,就容易維護困難。
如果你想保留SQL 裡面的字段名不動,可以手動取出數組,再賦值給對象:
<?php
$stmt = $pdo->query('SELECT id, user_name, email_address FROM users WHERE id = 1');
$data = $stmt->fetch(PDO::FETCH_ASSOC);
$user = new User();
$user->id = $data['id'];
$user->userName = $data['user_name'];
$user->emailAddress = $data['email_address'];
echo $user->userName; // 正確輸出
?>
這樣做靈活,但寫起來麻煩,每次都要手動賦值,不夠優雅。
如果你想更自動一點,可以寫一個小函數,把數據庫字段自動轉成駝峰命名,再賦值到對像上。
<?php
function snakeToCamel(string $string): string {
return lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $string))));
}
function mapToEntity(array $data, string $className) {
$object = new $className();
foreach ($data as $key => $value) {
$property = snakeToCamel($key);
if (property_exists($object, $property)) {
$object->$property = $value;
}
}
return $object;
}
// 使用示例
$stmt = $pdo->query('SELECT id, user_name, email_address FROM users WHERE id = 1');
$data = $stmt->fetch(PDO::FETCH_ASSOC);
$user = mapToEntity($data, 'User');
echo $user->userName; // 正確輸出
?>
這樣,你只需要寫一次轉換邏輯,後續所有查詢都可以自動處理了。
fetchObject適合簡單快速地獲取數據,如果需要復雜邏輯,建議使用ORM 框架(比如Laravel 的Eloquent、Symfony 的Doctrine 等)。
要確保實體類的屬性是public ,否則fetchObject無法直接賦值。
如果需要保護屬性,應該配合構造方法或者魔術方法__set()來處理賦值。
PDOStatement::fetchObject是一個方便但需要小心使用的功能。如果字段命名風格不同步,推薦在SQL 中使用別名,或者自己寫映射方法,這樣可以保持代碼整潔、健壯。對於中大型項目,更建議直接使用成熟的ORM 庫來管理實體映射,減少出錯風險。
如果你希望看到更多關於PDO、數據庫優化、或者實體映射的高級技巧,可以訪問我們的技術博客https://gitbox.net/blog查閱更多文章!