今天一个同事在Q群上考大家关于 php 的 count 函数的一些东东,大意是 count(‘some string’) 会输出什么……印象中,以前跟谁讨论过这个。不过日子久远,已经有些模糊了。所以还是写下来,just4fun。
大部分实践者都知道 count(string) 输出的结果是 1,而不是有的人期望的 strlen(string)。如果输出 count(callback),会惊奇的发现结果也是 1。这是为什么呢?
代码说明一切(php-5.2.11/ext/standard/array.c):
/* {{{ proto int count(mixed var [, int mode])
Count the number of elements in a variable (usually an array) */
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;
}
}
/* }}} */
可以发现在 319 行的 switch 分别判断了NULL(IS_NULL)、数组(IS_ARRAY)、对象(IS_OBJECT)和其他(default)。不论是 string 还是 callback 都被归类到了 default 里,所以在 350 行返回了长整形 1。也就是说除了 NULL、Array、Object 其他任何类型的数据 count 都只会返回 1。
通常,用 count 函数来计算数组的机会远大于对 NULL 值使用 count 函数。如果优化一下 case 的顺序,例如将 IS_ARRAY 放在 IS_NULL 的前面,可以减少那么一点点判断……当然了,现在的计算机性能,可能这点点优化是完全可以不必考虑的了。
——————– Just for fun 分割线 ————————–
如果期望 count(string) 返回 strlen(string) 的结果,其实只要在 switch 中增加一个 case 即可:
case IS_STRING:
RETURN_LONG (strlen(array));
break;
这个探讨没什么意义,好玩罢了……
这是不符合语义的,count是用来计算元素的个数,一个string应该是一个才是.,凡是count有多个的,都是能foreach的.你看object那块就知道了
ps:
说一点折腾的话,应该是如下才对,XD
case IS_STRING:
RETURN_LONG (Z_STRLEN(array));
break;
Countable和Iterater是两个接口呀