在 PHP 開發中,判斷陣列鍵是否存在是極高頻的操作。isset() 與 array_key_exists() 是兩個最常用的函數,但它們的語意、行為與效能特徵有本質差異。本文深入剖析兩者差異,並提供實務選擇指南。
| 特性 | isset() | array_key_exists() |
|---|---|---|
| 語意 | 檢查變數是否存在且不為 null | 檢查陣列中是否存在指定鍵(無論值為何) |
| 鍵值為 null 時 | 回傳 false | 回傳 true |
| 適用對象 | 變數、陣列元素、物件屬性 | 僅限陣列(或實作 ArrayAccess 的物件) |
| 語言結構 vs 函數 | 語言結構(language construct) | 函數呼叫 |
| 效能 | 極快(編譯器優化,無函數呼叫開銷) | 稍慢(函數呼叫開銷) |
| PHP 版本差異 | 所有版本一致 | PHP 8.0+ 可用 array_key_exists() 檢查物件屬性(配合 ArrayAccess) |
<?php
$a = ['key1' => '123', 'key2' => null, 'key3' => false, 'key4' => ''];
var_dump(isset($a['key1'])); // true
var_dump(isset($a['key2'])); // false ← 關鍵差異
var_dump(isset($a['key3'])); // true (false 非 null)
var_dump(isset($a['key4'])); // true (空字串非 null)
var_dump(array_key_exists('key1', $a)); // true
var_dump(array_key_exists('key2', $a)); // true ← 關鍵差異
var_dump(array_key_exists('key3', $a)); // true
var_dump(array_key_exists('key4', $a)); // true
var_dump(array_key_exists('key5', $a)); // false (鍵不存在)
?>
isset() 的設計目的是「檢查變數是否已被設定且非 null」。在 PHP 內部,未定義的變數與值為 null 的變數在 Zend 引擎的符號表中呈現相似狀態(IS_UNDEF vs IS_NULL),isset() 將兩者視為同樣「未被設定」。這符合 PHP 的弱型別哲學:null 代表「無值」,等同於未設定。
<?php
$arr = range(0, 9999);
$keys = array_flip($arr);
$iterations = 1000000;
$start = hrtime(true);
for ($i = 0; $i < $iterations; $i++) {
isset($arr[5000]);
}
$issetTime = hrtime(true) - $start;
$start = hrtime(true);
for ($i = 0; $i < $iterations; $i++) {
array_key_exists(5000, $arr);
}
$akeTime = hrtime(true) - $start;
echo "isset(): " . ($issetTime / 1e6) . " ms\n";
echo "array_key_exists(): " . ($akeTime / 1e6) . " ms\n";
echo "isset() 快約 " . round($akeTime / $issetTime, 1) . " 倍\n";
// 典型結果:isset() 快 3-5 倍
?>
$_GET、$_POST、$_SESSION 等isset($obj->prop)isset($a['b']['c']) 不會觸發錯誤null 的合法資料結構(如快取系統、資料庫 ORM 映射)ArrayAccess 介面的物件<?php
// 取得值,若鍵不存在或為 null 則用預設值
$value = $arr['key'] ?? 'default';
// 等同於
$value = isset($arr['key']) ? $arr['key'] : 'default';
?>
<?php
// 只需檢查陣列是否為空,不需特定鍵
if ($arr !== []) { ... }
// 或
if (count($arr) > 0) { ... }
?>
<?php
class User {
public $name;
private $email = null;
}
$user = new User();
var_dump(isset($user->name)); // false (未設定)
var_dump(isset($user->email)); // false (private 且為 null)
var_dump(property_exists($user, 'name')); // true
var_dump(property_exists($user, 'email')); // true
?>
isset($a['b']['c']) 安全;array_key_exists('c', $a['b'] ?? []) 需額外防護。array_key_exists() 接受陣列參考,大型陣列複製開銷大(PHP 7+ 寫時複製機制緩解此問題)。__isset() 只影響 isset(),不影響 array_key_exists()。預設使用 isset(),除非你明確需要區分「鍵不存在」與「值為 null」。在現代 PHP(7.4+)中,isset() 配合 ?? 運算子已能優雅處理 95% 以上的場景,兼具可讀性與極致效能。僅在領域模型明確要求「null 為合法值」時,才引入 array_key_exists()。