在一些面试或考试中经常会看到count函数的身影,于是一探其究竟
对于非数组的count处理
在其代码中可以看到
PHP_FUNCTION(count)
{
zval *array;
long mode = COUNT_NORMAL;
if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE)
return;
switch (Z_TYPE_P(array)) {
case IS_NULL: // 空值处理
RETURN_LONG(0);
break;
case IS_ARRAY: // 处理数组,包括其是递归
RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));
break;
case IS_OBJECT: {
#ifdef HAVE_SPL
/* it the object implements Countable we call its count() method */
zval *retval;
if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Countable TSRMLS_CC)) {
zend_call_method_with_0_params(&array, NULL, NULL, "count", &retval);
if (retval) {
convert_to_long_ex(&retval);
RETVAL_LONG(Z_LVAL_P(retval));
zval_ptr_dtor(&retval);
}
return;
}
#endif
/* if not we return the number of properties (not taking visibility into account) */
if (Z_OBJ_HT_P(array)->count_elements) {
RETVAL_LONG(1);
if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value) TSRMLS_CC)) {
return;
}
}
}
default: // 其它情况,如考试中常见的字符串等
RETURN_LONG(1);
break;
}
}
在手册中有说明:
此函数对于对象,如果安装了 SPL,可以通过实现 Countable 接口来调用 count()。该接口只有一个方法 count(),此方法返回 count() 函数的返回值。
对于数组长度的统计,如果mode使用默认值(0),则仅显示第一维数组的长度
如下所示代码
$arr = array(1, 2, 3);
$arr2 = array($arr, $arr);
echo count($arr2), '<br />';
echo count($arr2, 1);
/* 输出结果:
2
8
*/
如果只是显示第一维数组,则直接返回保存数组的HashTable的nNumOfElements属性即可
其实现的代码为:
// php_count_recursive函数 array.c 251行
cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
ZEND_API int zend_hash_num_elements(HashTable *ht)
{
IS_CONSISTENT(ht);
return ht->nNumOfElements;
}
如果想直接运行HashTable的一些简单操作,猛击PHP源码中HashTable的简单示例
如果想查看了解数组存储或遍历的方式,猛击鸟哥的深入理解PHP之数组(遍历顺序)
如果启动了递归,即使用count($arr, 1)
则程序会递归调用php_count_recursive函数
针对HashTable,程序会遍历包含这一维数组的双向链表,然后再递归遍历每个节点存储的pData,真到遍历完所有的节点
【感受】
HashTable很强大,如果要计算数组的长度还是调用count函数,重复发明轮子会是一种吃力不讨好的事情! |