关于 php 的 count 函数

今天一个同事在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;

这个探讨没什么意义,好玩罢了……

Join the Conversation

2 Comments

  1. 这是不符合语义的,count是用来计算元素的个数,一个string应该是一个才是.,凡是count有多个的,都是能foreach的.你看object那块就知道了

    ps:
    说一点折腾的话,应该是如下才对,XD

    case IS_STRING:
    RETURN_LONG (Z_STRLEN(array));
    break;

Leave a comment

Your email address will not be published. Required fields are marked *