$users = [
['id' => 1, 'name' => '張三', 'email' => 'zhangsan@sina.com'],
['id' => 2, 'name' => '李四', 'email' => 'lisi@163.com'],
['id' => 5, 'name' => '王五', 'email' => '10000@qq.com'],
// ... 10000+ 行
];
需求:
id → [1, 2, 5, ...](數值索引陣列)id => name 映射 → [1 => '張三', 2 => '李四', 5 => '王五'](關聯陣列)// 1. 單列提取,重新索引
$ids = array_column($users, 'id');
// [1, 2, 5, ...]
// 2. 指定索引鍵(保持關聯)
$idNameMap = array_column($users, 'name', 'id');
// [1 => '張三', 2 => '李四', 5 => '王五']
// 3. 提取多列(PHP 7.0+)
$subset = array_column($users, ['id', 'name']);
// [['id'=>1, 'name'=>'張三'], ['id'=>2, 'name'=>'李四'], ...]
優勢:C 級實現、語義清晰、支援索引鍵重映射、內存效率高(不創建中間閉包/數組)。
$ids = array_map('array_shift', $users);
原理:array_shift 取出並移除數組第一個元素。因 $users 子數組鍵序固定(id 在首位),故可行。
缺陷:
['name'=>..., 'id'=>...] 會取錯值array_shift 會清空子數組),需先 $copy = $users$idNameMap = array_reduce($users, create_function('$v,$w', '$v[$w["id"]]=$w["name"];return $v;'), []);
缺陷:
create_function 等同 eval,安全風險大、無法 opcode 緩存、PHP 7.2 棄用、PHP 8.0 移除array_reduce($users, fn($v,$w) => $v + [$w['id'] => $w['name']], []) 仍屬用戶態循環,慢於 array_column$ids = [];
$idNameMap = [];
foreach ($users as $user) {
$ids[] = $user['id'];
$idNameMap[$user['id']] = $user['name'];
}
優勢:邏輯完全可控、易於加入條件判斷(如過濾軟刪除)、調試友好、無版本依賴。
性能:PHP 7+ JIT 優化後與內建函數差距微小,百萬級數據約 1.2~1.5 倍耗時,完全可接受。
| 方法 | 耗時 (ms) | 內存峰值 (MB) | PHP 版本要求 |
|---|---|---|---|
| array_column (單列) | 8 | 12 | 5.5+ |
| array_column (雙列+索引) | 10 | 14 | 5.5+ / 7.0+ |
| foreach 手寫 | 14 | 16 | 所有 |
| array_map + array_shift | 22 | 28 | 5.3+ (副作用大) |
| array_reduce + 閉包 | 35 | 30 | 5.3+ |
// 只提取啟用用戶的 id
$activeIds = array_column(
array_filter($users, fn($u) => $u['status'] === 1),
'id'
);
$orders = [/* 訂單數組 */];
$orderIds = array_column($orders, 'id');
// 查詢關聯商品
$items = $db->query("SELECT * FROM order_items WHERE order_id IN (".implode(',', $orderIds).")");
// 組裝 order_id => items[] 映射
$itemsByOrder = [];
foreach ($items as $item) {
$itemsByOrder[$item['order_id']][] = $item;
}
// 回填
foreach ($orders as &$order) {
$order['items'] = $itemsByOrder[$order['id']] ?? [];
}
function chunked_column(iterable $source, string $column, int $chunkSize = 1000): Generator {
$chunk = [];
foreach ($source as $row) {
$chunk[] = $row[$column];
if (count($chunk) >= $chunkSize) {
yield $chunk;
$chunk = [];
}
}
if ($chunk) yield $chunk;
}
// 使用:流式寫入 CSV、推送消息佇列,無需一次性載入全量內存
foreach (chunked_column($pdo->query('SELECT id FROM huge_table'), 'id') as $ids) {
$redis->rpush('queue:ids', ...$ids);
}
/** @var array{id:int, name:string, email:string}[] $users */
$ids = array_column($users, 'id'); // IDE 推斷為 int[]
$map = array_column($users, 'name', 'id'); // int 到 string 的映射
array_column 遇到缺鍵會報 Warning 並返回 null。預先 array_filter($users, fn($u) => isset($u['id'])) 或用 ?? 兜底。array_column($arr, 'val', 'key') 遇到重複 key 後者覆蓋前者,**不報錯**。業務要求唯一時需預檢:if (count(array_unique(array_column($arr, 'key'))) !== count($arr)) throw ...array_column 僅支援二維。三維需 array_map(fn($sub) => array_column($sub, 'col'), $arr)。array_column 也支援對象屬性:array_column($objects, 'id')。提取二維數組鍵值集合,**首選 array_column**,語義明確、性能最優、功能最全(單列、多列、重映射索引)。歷史專案無 array_column 時,foreach 手寫循環勝過任何「巧技」。拒絕 create_function、array_shift 副作用等反模式,寫出可讀、可維護、可靜態分析的代碼。