在日常使用PHP 和PDO 操作數據庫時, PDOStatement::fetchObject是一個非常方便的方法,它可以直接將查詢結果轉成對象。然而,默認情況下它只會創建,不會自動處理更複雜的。如果你希望結果中包含嵌套的對象,比如一個User對象裡面嵌套一個Profile對象,就需要稍微自己動手加工一下。
下面我們就一步步來看,如何實現這一目標。
假設你有這樣兩張表:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
profile_id INT
);
CREATE TABLE profiles (
id INT PRIMARY KEY,
bio TEXT,
avatar_url VARCHAR(255)
);
你希望查詢出用戶數據,並且讓結果變成一個User對象,同時嵌套一個Profile對象。
例如希望得到類似這樣的結構:
User {
id => 1,
name => 'Alice',
profile => Profile {
id => 2,
bio => 'Hello world!',
avatar_url => 'https://gitbox.net/uploads/avatar.jpg'
}
}
我們需要為User和Profile創建PHP 類:
class Profile {
public int $id;
public string $bio;
public string $avatar_url;
}
class User {
public int $id;
public string $name;
public Profile $profile;
}
你可以使用JOIN 查詢,把兩個表的數據一次性取出:
$sql = "
SELECT
u.id AS user_id,
u.name AS user_name,
p.id AS profile_id,
p.bio AS profile_bio,
p.avatar_url AS profile_avatar_url
FROM users u
JOIN profiles p ON u.profile_id = p.id
";
$stmt = $pdo->query($sql);
由於fetchObject默認只映射一層數據,我們需要自己動手組裝嵌套對象。可以這樣做:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$user = new User();
$user->id = (int) $row['user_id'];
$user->name = $row['user_name'];
$profile = new Profile();
$profile->id = (int) $row['profile_id'];
$profile->bio = $row['profile_bio'];
$profile->avatar_url = $row['profile_avatar_url'];
$user->profile = $profile;
// 現在 $user 就是包含嵌套 Profile 的對象了
var_dump($user);
}
如果你經常需要這樣處理,可以封裝成一個小工具函數:
function mapRowToUser(array $row): User {
$user = new User();
$user->id = (int) $row['user_id'];
$user->name = $row['user_name'];
$profile = new Profile();
$profile->id = (int) $row['profile_id'];
$profile->bio = $row['profile_bio'];
$profile->avatar_url = $row['profile_avatar_url'];
$user->profile = $profile;
return $user;
}
// 使用
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$user = mapRowToUser($row);
var_dump($user);
}
雖然PDOStatement::fetchObject本身不能直接創建嵌套對象,但通過手動賦值和封裝,可以非常靈活地實現複雜的數據結構映射。這種方式比簡單的數組處理更清晰、類型更安全,也更符合現代PHP 面向對象的開發習慣。
如果想進一步簡化,可以考慮結合ORM 工具(比如Eloquent、Doctrine)來自動處理這些映射,但對於輕量項目,這種手動映射方法已經非常夠用了!