PHP 提供了多種檢查數組中值是否存在的函數,但性能、行為、適用場景差異巨大。本文深度對比 in_array、array_key_exists、array_search,提供選型指南和性能優化建議。
三大函數核心差異
| 函數 | 檢查對象 | 返回值 | 嚴格模式 | 時間複雜度 |
| in_array | 值 | bool | 第三參數 $strict | O(n) |
| array_key_exists | 鍵名 | bool | 不適用(鍵名嚴格) | O(1) 平均 |
| array_search | 值 | 鍵名/false | 第三參數 $strict | O(n) |
詳細用法與陷阱
1. in_array($needle, $haystack, $strict = false)
$arr = array('apple', 'banana', 'orange');
// 基礎用法(類型轉換比較)
var_dump(in_array('apple', $arr)); // true
var_dump(in_array(0, $arr)); // true! 'apple' == 0 為真
var_dump(in_array(false, $arr)); // true! 空字符串/0/false 相等
// 嚴格模式(類型+值雙重檢查)
var_dump(in_array('0', $arr, true)); // false
var_dump(in_array(0, $arr, true)); // false
// 陷阱:大數組性能極差
$big = range(1, 100000);
in_array(99999, $big); // 遍歷 10 萬次
2. array_key_exists($key, $array)
$arr = array('a' => 1, 'b' => 2, 0 => 'zero');
// 檢查鍵是否存在(包含 null 值的鍵)
var_dump(array_key_exists('a', $arr)); // true
var_dump(array_key_exists('c', $arr)); // false
var_dump(array_key_exists(0, $arr)); // true (數字鍵)
var_dump(array_key_exists(null, $arr)); // false
// 關鍵差異:isset() 返回 false 對於 null 值
$arr['d'] = null;
var_dump(isset($arr['d'])); // false
var_dump(array_key_exists('d', $arr)); // true ✅
3. array_search($needle, $haystack, $strict = false)
$arr = array('a' => 'apple', 'b' => 'banana', 'c' => 'apple');
// 返回第一個匹配的鍵名
var_dump(array_search('apple', $arr)); // 'a' (第一個)
var_dump(array_search('orange', $arr)); // false
// 嚴格模式
var_dump(array_search('0', array(0), true)); // false
// 獲取所有匹配鍵
$keys = array_keys($arr, 'apple'); // ['a', 'c']
性能實測與選型指南
測試環境:PHP 8.1,10萬元素數組,10000 次查找
| 場景 | 推薦函數 | 耗時(ms) | 內存 |
| 檢查值存在(小數組 <1000) | in_array | ~5 | 低 |
| 檢查值存在(大數組 >10000) | 翻轉鍵值 + array_key_exists | ~2 | 中 |
| 檢查鍵存在 | array_key_exists | ~1 | 低 |
| 需要獲取鍵名 | array_search | ~5 | 低 |
| 頻繁查找同一大數組 | 預建索引陣列 | ~0.5 | 高 |
大數組優化:翻轉鍵值法
// 原始數組:值為鍵,值為 true
$lookup = array_flip($bigArray); // O(n) 一次性構建
// 後續查找:O(1)
if (isset($lookup[$value])) { // 或 array_key_exists($value, $lookup)
// 存在
}
// 內存權衡:數組結構 array(1,2,3) vs array(1=>true, 2=>true)
// 內存比約 1:2,但查找快 100 倍以上
常見誤區與最佳實踐
| 誤區 | 正確做法 |
| 大數組用 in_array | 預建索引或 array_flip |
| 用 isset() 判斷鍵存在 | 值為 null 時失效,用 array_key_exists |
| 不加 strict 參數 | 嚴格模式避免類型轉換坑 |
| array_search 只判斷存在 | 不需要鍵名時用 in_array 更清晰 |
| 多維數組直接用這些函數 | 需遞歸或 array_column 提取單列 |
多維數組查找實用模式
$users = array(
array('id'=>1, 'name'=>'Alice', 'email'=>'alice@example.com'),
array('id'=>2, 'name'=>'Bob', 'email'=>'bob@example.com'),
);
// 1. 提取單列建立索引
$emails = array_column($users, 'email', 'id'); // [1=>'alice@...', 2=>'bob@...']
if (isset($emails[1])) { /* 存在 */ }
// 2. 搜索對象屬性
$found = array_filter($users, function($u) { return $u['name'] === 'Alice'; });
// 或
$keys = array_keys(array_column($users, 'name'), 'Alice'); // [0]
// 3. 遞歸搜索(深層嵌套)
function deepSearch($array, $needle, $strict = false) {
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = deepSearch($value, $needle, $strict);
if ($result !== false) return $result;
} elseif (($strict ? $value === $needle : $value == $needle)) {
return $key;
}
}
return false;
}
總結:決策流程圖
需要檢查什麼?
├── 鍵名存在? → array_key_exists() / isset() (值非null)
├── 值存在?
│ ├── 小數組/低頻? → in_array($val, $arr, true)
│ ├── 大數組/高頻? → array_flip() + isset() / array_key_exists()
│ └── 需要鍵名? → array_search($val, $arr, true)
└── 多維數組? → array_column() + 上述方法 / 遞歸搜索
更多 PHP 性能優化:《PHP 內核與性能優化》、《大數據量 PHP 處理技巧》