首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 物件陣列轉普通陣列最佳實作:遞迴處理 stdClass、巢狀結構、ThinkPHP 實戰場景

     編輯:PHP 相關知識

PHP 物件陣列轉普通陣列最佳實作

在使用 ThinkPHP/Laravel 等框架對接第三方 API(如京東服務市場)時,回傳資料常為 stdClass 物件陣列,需轉為純陣列才能配合 addAll() 批量寫入資料庫。本文提供健壯的遞迴轉換函數,支援多層巢狀物件、陣列混合結構,並解析核心原理與進階應用。

核心轉換函數

<?php
/**
 * 將 stdClass 物件(含巢狀)遞迴轉為純陣列
 * @param mixed $data 物件、陣列或標量值
 * @return array|mixed 轉換後的純陣列或原值
 */
function stdClassToArray($data) {
    // 1. 非物件/陣列直接返回
    if (!is_object($data) && !is_array($data)) {
        return $data;
    }

    // 2. 物件轉陣列(get_object_vars 獲取可見屬性)
    if (is_object($data)) {
        $data = get_object_vars($data);
    }

    // 3. 遞迴處理陣列每個元素
    $result = [];
    foreach ($data as $key => $value) {
        $result[$key] = stdClassToArray($value);
    }
    return $result;
}

// 別名函數(語義更清晰)
function objectToArray($data) {
    return stdClassToArray($data);
}
?>

實戰場景:ThinkPHP 批量寫入 API 回傳資料

<?php
// 模擬京東 API 回傳:物件陣列
$apiResponse = (object)[
    'code' => 0,
    'data' => [
        (object)[
            'sku_id' => 1001,
            'title' => '商品A',
            'price' => 99.00,
            'specs' => (object)[
                'color' => '紅色',
                'size'  => 'L',
                'tags'  => ['熱銷', '新品'] // 陣列中的字串
            ]
        ],
        (object)[
            'sku_id' => 1002,
            'title' => '商品B',
            'price' => 199.00,
            'specs' => (object)[
                'color' => '藍色',
                'size'  => 'XL'
            ]
        ]
    ]
];

// 1. 提取資料層
$items = $apiResponse->data; // 這是 stdClass 陣列

// 2. 轉換為純陣列
$itemsArray = stdClassToArray($items);

/*
結果結構:
[
    0 => [
        'sku_id' => 1001,
        'title' => '商品A',
        'price' => 99.00,
        'specs' => [
            'color' => '紅色',
            'size'  => 'L',
            'tags'  => ['熱銷', '新品']
        ]
    ],
    1 => [...]
]
*/

// 3. 直接批量寫入
$model = M('Product');
$model->addAll($itemsArray); // ThinkPHP 批量插入

echo "成功寫入 " . count($itemsArray) . " 筆資料";
?>

進階版:支援集合類別、生成器、DateTime 物件

<?php
function advancedObjectToArray($data, $options = []) {
    $defaultOptions = [
        'datetime_format' => 'Y-m-d H:i:s', // DateTime 輸出格式
        'preserve_keys'   => true,          // 保留數字鍵
        'max_depth'       => 50,            // 防無限遞迴
    ];
    $opts = array_merge($defaultOptions, $options);
    
    return _recursiveConvert($data, $opts, 0);
}

function _recursiveConvert($data, $opts, $depth) {
    if ($depth > $opts['max_depth']) {
        return '*MAX_DEPTH_REACHED*';
    }

    // 標量值直接返回
    if (is_scalar($data) || is_null($data)) {
        return $data;
    }

    // DateTime 物件格式化
    if ($data instanceof DateTime) {
        return $data->format($opts['datetime_format']);
    }

    // 實作 Traversable(集合、生成器、資料庫結果集)
    if ($data instanceof Traversable) {
        $data = iterator_to_array($data, $opts['preserve_keys']);
    }

    // 物件轉陣列
    if (is_object($data)) {
        // 避免遞迴:若已處理過(用 spl_object_id 標記)
        static $visited = [];
        $oid = spl_object_id($data);
        if (isset($visited[$oid])) {
            return '*CIRCULAR_REF*';
        }
        $visited[$oid] = true;
        
        $data = get_object_vars($data);
    }

    // 陣列遞迴
    if (is_array($data)) {
        $result = [];
        foreach ($data as $key => $value) {
            $result[$key] = _recursiveConvert($value, $opts, $depth + 1);
        }
        return $result;
    }

    return $data;
}
?>

框架內建方法對比

框架/庫方法特點
Laravelcollect($obj)->toArray() / $obj->toArray() (Model)Collection 強大、支援鏈式操作、自動處理關聯
SymfonyPropertyAccess::createPropertyAccessor()屬性存取器、支援 getter/setter、序列化器整合
ThinkPHP 5/6collection($obj)->toArray() / model->toArray()內建集合類、模型自動轉換
Yii 2ArrayHelper::toArray($obj)支援自定義轉換規則、關聯展開控制
原生 PHPjson_decode(json_encode($obj), true)簡潔但效能較差、DateTime 變字串、private 屬性丟失

json_encode/decode 大坑警示

<?php
$obj = new stdClass();
$obj->public = 'ok';
$obj->private = 'secret'; // 實際上 PHP 物件無 private 動態屬性,這裡指類別定義的 private

class Test {
    public $pub = 'pub';
    private $pri = 'pri';
    protected $pro = 'pro';
}

$t = new Test();
// json_encode 只能獲取 public 屬性!
echo json_encode($t); // {"pub":"pub"}  → private/protected 丟失!

// get_object_vars 同樣只能獲取可見屬性(呼叫上下文決定)
// 類別內部可獲取 private/protected,外部只能獲取 public
?>

結論: 簡單場景用 json_decode(json_encode($obj), true) 最快;複雜/生產環境請用框架內建或上文遞迴函數,確保完整性與型別正確。

效能優化建議

  • 大量資料: 避免逐筆轉換,直接在資料庫查詢層返回陣列(PDO::FETCH_ASSOC、Eloquent ->toArray()、ThinkPHP Db::query())。
  • 記憶體: 生成器模式處理超大結果集,逐行轉換寫入,避免一次載入所有物件。
  • 快取: 相同 API 回傳結構可快取轉換後結構(Key: api_response_hash)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved