曾有一次面试时面试官问我
count('abc')
会返回多少。当时我一下子懵了,不带这样玩的啊,count 函数不是用来计算数组元素个数的么,你传个字符串进去是几个意思啊。然后我满脸疑问并不自信的回答,是 3 吗,因为我觉得 PHP 的字符串也有时候可以表现得像数组,比如你可以用下标来取到字符串中对应位置的字符。面试官说是 1,然后我说没这样用过,一般都是用 count 来计算数组元素个数,面试官说,这就说明你代码量不够了。
写了简单文件,我们来看看给 count 函数传入非数组的参数时会返回什么:
<?php var_dump(count('abc')); var_dump(count('')); var_dump(count(0)); var_dump(count(false)); var_dump(count(null)); $books = array( array( 'name' => 'Pairs', 'price' => 30, ), array( 'name' => 'Apple', 'price' => 20, ), ); var_dump(count($books)); var_dump(count($books, COUNT_RECURSIVE));
上面代码输出如下:
int(1) int(1) int(1) int(1) int(0) int(2) int(6)
可以看到 count 在作用于非数组的变量时,除了 null,其它都返回 1,为什么会这样呢,我们来看看 PHP 有关于 count 函数的 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 zval *retval; #endif /* first, we check if the handler is defined */ 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; } } #ifdef HAVE_SPL /* if not and the object implements Countable we call its count() method */ 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 } default: RETURN_LONG(1); break; } } /* }}} */
源码很明显,如果传入的参数为 null,则返回 0,如果传入的数组,则计算数组元素个数,如果是对象,则按对象进行相应处理(这个过程我不是太明白),重点在于最后的 default,也就是说其它任何类型都返回 1.
完。