在动态类型的PHP中,我们可以创建可以接受多种数据类型作为参数的函数。然后,我们可以根据变量的类型对数据进行操作。有两种方法可以做到这一点:
接近一个:
function doSomething1($param) {
$type = gettype($param);
if ($type === 'string') {
// do something
}
else if ($type === 'integer') {
// do something
}
else if ($type === 'array') {
// do something
}
}
接近两个:
function doSomething2($param) {
if (is_string($param)) {
// do something
}
else if (is_int($param)) {
// do something
}
else if (is_array($param)) {
// do something
}
}
据我所知,从测试的角度来看,这两种方法在功能上是等价的,但由于PHP有很多问题,所以如果我赞成采用另一种方法,我会问我是否有什么可以错过的?
从绩效的角度来看,将方法一比两个更快是正确的,因为PHP function calls are expensive?或者gettype()
比单个is_*()
函数更昂贵的操作?
是否有关于此的编码习语/风格指南?
更新
根据我使用PHP 7.0.4的基准测试,一百万次doSomething2()
次迭代耗时159ms,略低于doSomething1()
的一半时间,为315ms。无论是否传入字符串(第一次检查)或数组(最后一次检查),都是如此。这似乎表明gettype()
确实是一项昂贵的操作,并且比使用is_*()
的多个函数调用更昂贵
如果有人更深入了解这可能是什么原因,我们将非常感谢您的帮助。
答案 0 :(得分:3)
让我们比较gettype
和is_string
函数的C代码。
gettype
:
PHP_FUNCTION(gettype)
{
zval *arg;
zend_string *type;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(arg)
ZEND_PARSE_PARAMETERS_END();
type = zend_zval_get_type(arg);
if (EXPECTED(type)) {
RETURN_INTERNED_STR(type);
} else {
RETURN_STRING("unknown type");
}
}
因此,它将创建字符串type
,并通过调用函数zend_zval_get_type
的结果来填充它,即:
ZEND_API zend_string *zend_zval_get_type(const zval *arg) /* {{{ */
{
switch (Z_TYPE_P(arg)) {
case IS_NULL:
return ZSTR_KNOWN(ZEND_STR_NULL);
case IS_FALSE:
case IS_TRUE:
return ZSTR_KNOWN(ZEND_STR_BOOLEAN);
case IS_LONG:
return ZSTR_KNOWN(ZEND_STR_INTEGER);
case IS_DOUBLE:
return ZSTR_KNOWN(ZEND_STR_DOUBLE);
case IS_STRING:
return ZSTR_KNOWN(ZEND_STR_STRING);
case IS_ARRAY:
return ZSTR_KNOWN(ZEND_STR_ARRAY);
case IS_OBJECT:
return ZSTR_KNOWN(ZEND_STR_OBJECT);
case IS_RESOURCE:
if (zend_rsrc_list_get_rsrc_type(Z_RES_P(arg))) {
return ZSTR_KNOWN(ZEND_STR_RESOURCE);
} else {
return ZSTR_KNOWN(ZEND_STR_CLOSED_RESOURCE);
}
default:
return NULL;
}
}
让我们与is_string
进行比较,例如:
PHP_FUNCTION(is_string)
{
php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_STRING);
}
转到php_is_type
:
static inline void php_is_type(INTERNAL_FUNCTION_PARAMETERS, int type)
{
zval *arg;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(arg)
ZEND_PARSE_PARAMETERS_END();
if (Z_TYPE_P(arg) == type) {
if (type == IS_RESOURCE) {
const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(arg));
if (!type_name) {
RETURN_FALSE;
}
}
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
因此,这些方法的核心逻辑是完全相同的– PHP使用Z_TYPE_P
来检测变量的类型。
但是在gettype
的情况下,它还会为结果创建附加字符串,并用常量字符串填充它,而不是在is_*
函数的情况下仅返回布尔TRUE或FALSE。
因此,肯定is_*
函数会更快:)