count() 是 PHP 中使用頻率極高的函數,用於統計陣列元素個數或實作 Countable 介面的物件屬性數量。本文基於 PHP 5.4+ 源碼,從函數簽名、參數行為、核心實現流程、遞迴計數機制、物件處理邏輯等維度深度剖析其內部運作原理。
int count ( mixed $array_or_countable [, int $mode = COUNT_NORMAL ] )
Countable 介面的物件;其他型別(整數、字串、一般物件)均回傳 1;null 回傳 0。$mode:
COUNT_NORMAL(預設,值 0):僅計算第一層元素數量。COUNT_RECURSIVE(值 1):遞迴計算多維陣列所有層級元素總和。E_WARNING 並回傳大於預期的值。function count($var, $mode = COUNT_NORMAL) {
switch (Z_TYPE_P(var)) {
case IS_NULL:
return 0;
case IS_ARRAY:
return php_count_recursive(var, mode);
case IS_OBJECT:
// 1. 檢查是否為 array-like object (繼承 ArrayObject)
if (Z_OBJ_HT_P(var)->count_elements) {
return Z_OBJ_HT_P(var)->count_elements(var);
}
// 2. 檢查是否實作 Countable 介面
if (instanceof_function(Z_OBJCE_P(var), spl_ce_Countable)) {
return zend_call_method(var, 'count', ...);
}
// 3. 一般物件回傳 1
return 1;
default: // string, int, float, bool, resource
return 1;
}
}
php_count_recursive位於 ext/standard/array.c,核心邏輯:
HashTable 的 nNumOfElements 直接取得當前層級元素數(O(1))。mode == COUNT_RECURSIVE,遍歷每個元素,若值為陣列則遞迴呼叫自身累加。u.v.nApplyCount 計數器,遞迴進入時 ++,離開時 --;若偵測到 nApplyCount > 1 則觸發 E_WARNING「Recursion detected」,防止無限迴圈。count_elements 處理器當物件繼承 ArrayObject 且實作 count() 方法時,PHP 內核會在物件的 zend_object_handlers 中設定 count_elements 指向內部處理函數,最終呼叫使用者定義的 count() 方法。若未實作 count(),預設回傳 0。
實作 Countable 介面的類別必須定義 public function count(): int。PHP 執行 count($obj) 時,透過 instanceof_function 判斷,再呼叫 zend_call_method 執行使用者方法,直接返回其整數結果。
| 程式碼 | count() 結果 | count($arr, 1) 結果 | 說明 |
|---|---|---|---|
$a = [1,2,3,4,5]; | 5 | 5 | 一維陣列 |
$b = ['a','b',['c','d'],'e']; | 4 | 6 | 多維陣列遞迴計數 |
$str = "hello"; | 1 | 1 | 非陣列/非 Countable 物件 |
class A extends ArrayObject { public function count(){return 2;} } | 2 | 2 | ArrayObject 子類 |
class B implements Countable { public function count(){return 3;} } | 3 | 3 | Countable 介面 |
count():// 差:每次迴圈都計算
for ($i=0; $i < count($arr); $i++) { ... }
// 優:預先儲存
$len = count($arr);
for ($i=0; $i < $len; $i++) { ... }
COUNT_RECURSIVE:遞迴遍歷會消耗大量 CPU 與記憶體,必要時改用迭代器或自定義計數邏輯。count((array)$obj)。ext/standard/array.c → php_if_count()ext/standard/array.c → php_count_recursive()Zend/zend_object_handlers.c → zend_std_count_elements()ext/spl/spl_iterators.c → spl_ce_Countable理解 count() 的底層實現,不僅能寫出更高效的程式碼,也能在除錯遞迴陣列、設計自定義集合類別時做出正確決策。建議開發者閱讀 PHP 官方源碼倉庫中的相關檔案,並關注 PHP 8.x 版本對 count() 的優化(如 JIT 加速、型別系統增強)。