前言
count() 是 PHP 計算陣列元素個數、物件可數屬性、或標量值「單元數」的核心函數。看似簡單,實則隱藏多個新手易踩的坑。本文將徹底解析其行為、參數模式、常見誤區與現代最佳實踐。
函數原型
count(Countable|array $value, int $mode = COUNT_NORMAL): int
COUNT_NORMAL(預設,0):不遞迴計算多維陣列。
COUNT_RECURSIVE(1):遞迴計算多維陣列所有元素總數。
核心行為對照表
| 輸入類型 | 輸入範例 | 返回值 | 說明 |
| 索引陣列 | [1,2,3] | 3 | 正常計算 |
| 關聯陣列 | ['a'=>1,'b'=>2] | 2 | 正常計算 |
| 空陣列 | [] | 0 | 正常 |
| 未初始化變數 | $undef | 0 | 不報錯,返回 0(易誤判) |
null | null | 0 | 特例 |
| 標量(int/float/string/bool) | 123 / "abc" / true | 1 | 視為 1 個單元 |
| 物件 | new stdClass() | 1 | 預設 1;實作 Countable 則呼叫 count() |
| 資源 | fopen(...) | 1 | 視為 1 個單元 |
三大經典陷阱
陷阱一:未初始化變數返回 0,與空陣列無法區分
<?php
// 未定義 $arr
if (count($arr) > 0) { ... } // 不會進入,但也沒有警告(PHP 8.0+ 可能有 deprecation)
// 正確做法:先檢查是否存在
if (isset($arr) && count($arr) > 0) { ... }
// 或 PHP 7.0+
if (($arr ?? []) !== []) { ... }
// 或直接用 empty() 反向邏輯(注意 empty('0') 為 true)
if (!empty($arr)) { ... }
陷阱二:COUNT_RECURSIVE 計算方式易誤解
<?php
$arr = [
'a' => [1, 2],
'b' => [3, 4, 5]
];
echo count($arr); // 2 (頂層元素)
echo count($arr, COUNT_RECURSIVE); // 7 = 2(頂層鍵) + 2 + 3 (子元素)
// 並非單純「所有葉子節點總和」,會包含每層鍵的計數
陷阱三:Countable 介面實作錯誤導致無限遞迴
<?php
class BadCollection implements Countable {
private $items = [];
public function count(): int {
return count($this->items); // 正確:委託內部陣列
}
}
class EvilCollection implements Countable {
public function count(): int {
return count($this); // 錯誤!觸發 __invoke 或無限遞迴(PHP 7.2+ 會拋錯)
}
}
現代最佳實踐(PHP 7.4+)
1. 判斷「非空陣列」首選 !empty() 或 ?? []
$items = $data['items'] ?? [];
if ($items) { ... } // 空陣列為 false,非空為 true
2. 物件集合實作 Countable + IteratorAggregate
<?php
class UserCollection implements Countable, IteratorAggregate {
private array $users = [];
public function add(User $user): self { $this->users[] = $user; return $this; }
public function count(): int { return count($this->users); }
public function getIterator(): Traversable { return new ArrayIterator($this->users); }
}
$col = new UserCollection();
$col->add(new User())->add(new User());
echo count($col); // 2
foreach ($col as $user) { ... } // 可直接遍歷
3. 避免在循環條件中重複呼叫 count()
<?php
// 慢
for ($i = 0; $i < count($bigArray); $i++) { ... }
// 快
$len = count($bigArray);
for ($i = 0; $i < $len; $i++) { ... }
// 更現代:foreach
foreach ($bigArray as $item) { ... }
4. 多維陣列總葉子數計算(遞迴或扁平化)
<?php
function countLeaves(array $arr): int {
$count = 0;
array_walk_recursive($arr, function() use (&$count) { $count++; });
return $count;
}
// 或
$count = count(array_merge(...array_values($arr))); // 仅限二维数组
效能對比
| 操作 | 時間複雜度 | 備註 |
count($arr) | O(1) | PHP 內部維護元素計數器 |
count($arr, COUNT_RECURSIVE) | O(n) | 需遞迴遍歷 |
sizeof($arr) | O(1) | count 別名,建議統一用 count |
總結
count() 對陣列為 O(1),極快,放心使用。
- 未定義變數返回 0 不報錯,務必配合
isset() 或 ?? [] 使用。
- 標量/物件/資源均返回 1,非陣列語境下極易誤判,嚴格檢查
is_array()。
- 現代代碼優先用
foreach、!empty()、?? [] 替代直接 count() 判斷。
- 自定集合類實作
Countable 即可原生支援 count()。
- 上一篇文章: PHP 陣列處理函數完整速查表:分類、範例與現代替代方案
- 下一篇文章: 使用 PHP 創建與修改 PDF 文檔:TCPDF 深度實戰指南
Copyright ©
程式碼之家 All Rights Reserved