在 Yii 1.x 開發中,CArrayDataProvider 與 CActiveDataProvider 是兩大核心數據提供者,廣泛用於 CGridView、CListView 等數據展示組件。本文通過實例對比兩者的數據來源、適用場景、配置差異,助您精準選型。
| 維度 | CArrayDataProvider | CActiveDataProvider |
|---|---|---|
| 數據來源 | PHP 數組(任意結構) | ActiveRecord 模型類(關聯數據庫表) |
| 典型場景 | 非 AR 數據:外部 API、多表聯查、臨時計算、緩存數組 | 基於單表或關聯表的 AR 模型查詢 |
| 分頁/排序 | 需手動處理或配置 pagination/sort | 內建支持 criteria、pagination、sort |
| 性能特點 | 全量數組載入內存,大數據量慎用 | 配合 CDbCriteria 可生成高效 SQL(含 LIMIT/OFFSET) |
場景:從另一個數據庫連接(marketdb)查詢 tbl_count2 表,結果以數組形式返回,需分頁展示。
// 1. 執行原生 SQL 查詢(跨庫/複雜聯查/存儲過程等)
$sql = "SELECT * FROM tbl_count2 ORDER BY id DESC";
$data = Yii::app()->marketdb->createCommand($sql)->queryAll(); // 返回二維數組
// 2. 封裝為 CArrayDataProvider
$dataProvider = new CArrayDataProvider($data, array(
'pagination' => array(
'pageSize' => 16, // 每頁 16 條
),
// 可選:啟用排序
'sort' => array(
'attributes' => array('id', 'name', 'created_at'),
'defaultOrder' => 'id DESC',
),
));
// 3. 視圖中直接傳給 CGridView
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $dataProvider,
'columns' => array('id', 'name', 'count', 'created_at'),
));
queryAll() 會將所有結果載入內存。若源表超過萬行,請改用 query() 返回 CDbDataReader 迭代處理,或在 SQL 層面做 LIMIT。ORDER BY。場景:基於 PhotoAttachment 模型,按條件篩選、倒序分頁。
$condition = array();
// 構建條件數組,例如:
// $condition[] = "status = 1";
// $condition[] = "user_id = " . Yii::app()->user->:id;
$dataProvider = new CActiveDataProvider('PhotoAttachment', array(
'pagination' => array(
'pageSize' => 20,
),
'criteria' => array(
'condition' => implode(' AND ', $condition), // WHERE 子句
'order' => 'id DESC', // ORDER BY
// 'with' => array('author'), // 急加載關聯(可選)
),
));
LIMIT 20 OFFSET 0,內存常數級with 支持急加載,避免 N+1 問題CGridView 自動讀取 sort、pagination 參數生成分頁鏈接需要展示的數據來源是否為 ActiveRecord 模型?
├── 是 → 直接使用 CActiveDataProvider
│ ├── 需要複雜關聯查詢?→ 配合 criteria.with 使用
│ ├── 需要自定義 SELECT 字段?→ criteria.select = 'id, name'
│ └── 需要動態條件構建?→ 使用 CDbCriteria 對象構建
└── 否(數組/外部API/多表聯查結果/緩存數據)
├── 數據量 < 5000 行?→ CArrayDataProvider 可接受
│ └── 需要排序/分頁?→ 配置 sort/pagination 參數
└── 數據量 ≥ 5000 行?
├── 能否推到 SQL 層做 LIMIT?→ 改用 CSqlDataProvider
└── 必須全量 PHP 處理?→ 考慮分批處理/異步隊列/緩存預計算
若需「原生 SQL 查詢」+「數據庫級分頁/排序」,CSqlDataProvider 是更佳選擇:
$count = Yii::app()->db->createCommand("SELECT COUNT(*) FROM tbl_count2 WHERE status=1")->queryScalar();
$dataProvider = new CSqlDataProvider(
"SELECT * FROM tbl_count2 WHERE status=1 ORDER BY id DESC",
array(
'totalItemCount' => $count,
'pagination' => array('pageSize' => 16),
'sort' => array('attributes' => array('id', 'name')),
)
);
CSqlDataProvider 會自動在 SQL 外層包裹 LIMIT/OFFSET,兼具靈活性與性能。
實際開發中,80%+ 場景使用 CActiveDataProvider;跨庫報表、臨時計算結果展示用 CArrayDataProvider;複雜報表 SQL 直出用 CSqlDataProvider。