PHP stdClass 完整指南:動態物件建構、屬性存取與陣列轉換實戰
stdClass 是 PHP 內建的「空白類別」,無任何預設屬性與方法。它是動態建構資料物件、API 回傳值封裝、陣列轉物件的首選工具。本文全面解析建構方式、屬性操作、巢狀結構存取、陣列互轉與常見陷阱。
什麼是 stdClass?
- PHP 核心預定義類別,Zend Engine 保留。
- 無建構子、無方法、無預設屬性。
- 實例化後可動態新增屬性(類似 JavaScript 物件)。
- 所有
(object) $array 轉換結果皆為 stdClass 實例。
建構方式對比
| 方式 | 代碼 | 特點 |
| 實例化 + 動態屬性 | $obj = new stdClass(); $obj->id = 1; | 最直觀、效能最好 |
| 陣列強制轉型 | $obj = (object) ['id' => 1]; | 一行建構、適合陣列轉換 |
| JSON 解碼 | $obj = json_decode($json); | API 回應處理首選、預設回傳 stdClass |
| 匿名類別 (PHP 7+) | $obj = new class { public $id = 1; }; | 可定義方法、更靈活但較重 |
屬性存取與操作
<?php
$obj = new stdClass();
$obj->id = 11;
$obj->username = 'me';
$obj->tags = ['php', 'stdclass'];
// 讀取
echo $obj->id; // 11
echo $obj->username; // me
// 判斷屬性存在
isset($obj->id); // true
isset($obj->email); // false
property_exists($obj, 'id'); // true (即使值為 null 也為 true)
// 刪除屬性
unset($obj->tags);
// 取得所有屬性 (陣列形式)
$props = get_object_vars($obj);
// ['id' => 11, 'username' => 'me']
?>
巢狀 stdClass 結構存取 (API 回應常見)
<?php
// 模擬天氣 API 回應
$weather = json_decode('{
"getWeatherbyCityNameResult": {
"string": ["四川", "成都", "56294", "56294.jpg", "2009-5-17 13:52:08", "26℃/19℃", "5月17日 陰轉陣雨"]
}
}');
// 存取方式:物件屬性 -> 陣列索引
echo $weather->getWeatherbyCityNameResult->string[0]; // 四川
echo $weather->getWeatherbyCityNameResult->string[1]; // 成都
// 若屬性名含特殊字元,用大括號語法
$obj->{'special-key'} = 'value';
echo $obj->{'special-key'};
?>
陣列與 stdClass 雙向轉換
<?php
// 陣列 → stdClass
$arr = ['id' => 1, 'name' => 'John'];
$obj = (object) $arr;
// 或
$obj = json_decode(json_encode($arr)); // 深度轉換,處理巢狀陣列
// stdClass → 陣列
$arr2 = (array) $obj;
// 或
$arr2 = get_object_vars($obj); // 僅取得可見屬性
// 注意:(array) 轉換會保留 protected/private 屬性 (鍵名含特殊字元)
// get_object_vars() 僅回傳公開屬性,較乾淨
?>
進階陷阱:new stdClass() 會清空先前轉換資料
<?php
$arr = [1 => 2, 2 => 3];
$obj = (object) $arr; // stdClass { [1]=>2, [2]=>3 }
$obj->id = 11; // 新增屬性
$obj2 = new stdClass(); // 重新實例化!
$obj2->id = 11;
$obj2->username = 'me';
// $obj 保留原陣列資料 + 新增屬性
// $obj2 僅有新增屬性,原陣列資料遺失
?>
最佳實踐建議
- API 回應處理:
json_decode($response, false) 直接得到 stdClass 物件樹,配合 -> 鏈式存取最直觀。
- 資料傳遞物件 (DTO):簡單場景用 stdClass 替代建立正式類別,但不可加入方法,僅作為資料容器。
- 避免在函式中搭配 global/static 使用
&new stdClass:參考傳遞新實例化物件在某些 PHP 版本有行為差異,直接用 new stdClass()。
- 型別提示 (PHP 7.1+):可用
stdClass 作為型別提示,但無法限制屬性結構,嚴謹場景建議定義介面或具體類別。
stdClass vs 關聯陣列:如何選擇?
| 場景 | 推薦 | 理由 |
| 單純資料儲存/傳遞 | 關聯陣列 | 語法簡潔、內建函式豐富、效能略優 |
| API JSON 解碼後直接使用 | stdClass | 避免轉換開銷、-> 存取更符合物件語意 |
| 需動態新增/刪除屬性 | stdClass | 語意清晰、unset($obj->prop) 比 unset($arr['key']) 更明確 |
| 需序列化/反序列化 | 皆可 | serialize() 兩者支援度相同 |