在PHP程式設計中,在遍歷陣列的時候經常需要先計算陣列的長度作為迴圈結束的判斷條件,而在PHP裡面對陣列的操作是很頻繁的,因此count也算是一個常用函式,下面研究一下count函式的具體實現。
我在github有對PHP原始碼更詳細的註解。感興趣的可以圍觀一下,給個star。PHP5.4原始碼註解。可以通過commit記錄檢視已新增的註解。
count
1 |
int count ( mixed $array_or_countable [, int $mode = COUNT_NORMAL ] ) |
count函式計算陣列或者物件裡面的所有元素個數。
對於物件來說,如果你安裝了SPL擴充套件,可以通過實現Countable介面來呼叫count函式。Countable介面有且僅有一個方法Countable::count(),該方法的返回count()函式的返回值。
引數說明
mode
如果引數mode設為COUNT_RECURSIVE(或1),count()會遞迴地計算該陣列。在計算多維陣列的時候特別有用。
如果第一個引數不是陣列或者實現Countable介面的物件,count函式將返回1。
注意:count函式可以檢測遞迴避免無限迴圈,但會在遇到無限遞迴或得到比期望值大的時候返回E_WARNING提示。
執行示例
普通應用
1 2 |
$arr1 = array(1, 2, 3, 4, 5); $val1 = count($arr1); // 5 |
多維陣列
1 2 3 |
$arr2 = array('apple', 'banana', array('cat', 'camel'), 'dog'); $val2_1 = count($arr2); // 4 $val2_2 = count($arr2, 1); // 6 |
數字和字串
1 2 3 4 |
$str = "hello world"; $int_val = 1; $val3 = count($str); // 1 $val4 = count($int_val); // 1 |
普通物件
1 2 3 4 5 6 7 8 |
class User { private $name; private $address; } $user = new User(); $val5 = count($user); // 1 $val6 = count((array) $user); // 2 |
array-like物件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class User extends ArrayObject { private $name; public function __construct() { $this->name = 'hhq'; } public function getName() { return $this->name; } public function count() { return 2; } } $user2 = new User(); $val7 = count($user2); // 2 |
實現Countable介面物件
1 2 3 4 5 6 7 8 |
class User implements Countable { public function count() { return 3; } } $user3 = new User(); $val8 = count($user3); // 3 |
執行步驟
進入switch語句檢測引數型別
如果是NULL,直接返回0
如果是陣列,呼叫php_count_recursive函式機選陣列元素個數
如果是物件,先檢查是否為陣列物件(array-like object),如果是,則計算陣列物件的數量
否則,如果物件實現了Countable介面,則呼叫Countable的count方法
最後,其他型別比如整型陣列或字串,都返回1。
原始碼解讀
如果是普通陣列,count函式會呼叫php_count_recursive函式實現其功能的執行步驟如下:
如果當前hash Bucket被遞迴訪問的次數大於1,說明重複遞迴,染回E_WARNING錯誤
否則計算當前陣列層數的陣列元素個數
如果有遞迴引數選項,則繼續遞迴訪問
如果引數是物件型別,實現時會先判斷handler是否被定義。而handler是PHP核心中物件的結構體,其中包含有count_elements欄位,實際上是一個函式。如果某個物件表現得想陣列一樣,即通常說的array-like object,那麼就會執行count_elements函式。具體實現是類繼承PHP的ArrayObject,並在類裡面實現count函式,具體呼叫的就是count函式,如果類沒有實現count函式,則count返回0,否則返回物件的count函式的返回值。
如果是其他的資料型別 1、字串
2、數字
3、物件分支中兩個if判斷都為false的情況,即沒有繼承ArrayObject且沒有實現Countable介面。
這些型別通通返回1。
需要注意的是,如果需要計算的是物件的屬性數量,可以先將物件轉換成陣列,然後呼叫count函式。如: $count_value = count((array) $user);
小結
閱讀count函式的原始碼過程中,在其中一步卡住了,就是if (Z_OBJ_HT_P(array)->count_elements)這一步,因為始終無法寫出進入這個分支的demo,在網上搜尋了很多資料也未果,因此請教了TIPI的reeze,最終得到了想要的答案。不懂就要問,哈哈。
原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
如果本文對你有幫助,請點下推薦吧,謝謝^_^
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式