深入理解 PHP 之 count 函数

曾有一次面试时面试官问我

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.

完。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注