几道无聊的php的比较运算题,有兴趣的玩一玩

简介:

趣题:
下面的几段代码分别输出true or false?

​第一个:


<?php
$key=1;
var_dump($key == " \t01ab");
?>

第二个:


<?php
$key='1';
var_dump($key == " \t01ab");
?>

第三个:


<?php
$key=0;
var_dump($key == " \t01ab");
?>

第四个:


<?php
$key=0;
var_dump($key == " \t00ab");
?>

第五个:


<?php
$key=0;
var_dump($key == " ab");
?>

第六个:


<?php
$key='0';
var_dump($key == " ab");
?>

答案:
第一道:true

第二道:false

第三道:false

第四道:true

第五道:true

第六道:false

题解:
当比较的一方是数字时,字符串会转换成数字,然后再进行比较。

如果比较的两方全部为字符串时,当然就不存在转换,只是单纯的进行字符串比较了。

需要注意的是,字符串转换成数字时,如果字符串被视为十进制格式时,大概的转换规则如下:

1.过滤前面的一些字符。这些字符包括 空格,'\t' ,'\n' , '\r' ,'\v' , '\f' 和 0

2.把后面不是数字的字符和之后字符也过滤掉。如 123abc4 就会把a和之后的字符过滤掉。

思考题:
如果前面的== 改成 === 结果如何?
下面的代码输出true or false?


<?PHP
$a = 0;
if(in_array($a, array('index', 'post'))){
    echo "true";
}else{
    echo "false";
}
?>

进阶:
以上只是大概的转换规则,可能有说的不严谨的地方。具体的规则大家可以查看源码:

zend/zend_operators.c:1402行
这个方法说明了比较时,各种情况下比较规则。


ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
    int ret;
    int converted = 0;
    zval op1_copy, op2_copy;
    zval *op_free;
 
    while (1) {
        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
            case TYPE_PAIR(IS_LONG, IS_LONG):
                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
                return SUCCESS;
 
            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
                return SUCCESS;
 
            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
                return SUCCESS;
 
            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
                    ZVAL_LONG(result, 0);
                } else {
                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
                }
                return SUCCESS;
 
            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
                zend_compare_arrays(result, op1, op2 TSRMLS_CC);
                return SUCCESS;
 
            case TYPE_PAIR(IS_NULL, IS_NULL):
                ZVAL_LONG(result, 0);
                return SUCCESS;
 
            case TYPE_PAIR(IS_NULL, IS_BOOL):
                ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
                return SUCCESS;
 
            case TYPE_PAIR(IS_BOOL, IS_NULL):
                ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
                return SUCCESS;
 
            case TYPE_PAIR(IS_BOOL, IS_BOOL):
                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
                return SUCCESS;
 
            case TYPE_PAIR(IS_STRING, IS_STRING):
                zendi_smart_strcmp(result, op1, op2);
                return SUCCESS;
 
            case TYPE_PAIR(IS_NULL, IS_STRING):
                ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
                return SUCCESS;
 
            case TYPE_PAIR(IS_STRING, IS_NULL):
                ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0));
                return SUCCESS;
 
            case TYPE_PAIR(IS_OBJECT, IS_NULL):
                ZVAL_LONG(result, 1);
                return SUCCESS;
 
            case TYPE_PAIR(IS_NULL, IS_OBJECT):
                ZVAL_LONG(result, -1);
                return SUCCESS;
 
            case TYPE_PAIR(IS_OBJECT, IS_OBJECT):
                /* If both are objects sharing the same comparision handler then use is */
                if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) {
                    if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
                        /* object handles are identical, apparently this is the same object */
                        ZVAL_LONG(result, 0);
                        return SUCCESS;
                    }
                    ZVAL_LONG(result, Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC));
                    return SUCCESS;
                }
                /* break missing intentionally */
 
            default:
                if (Z_TYPE_P(op1) == IS_OBJECT) {
                    if (Z_OBJ_HT_P(op1)->get) {
                        op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
                        zend_free_obj_get_result(op_free TSRMLS_CC);
                        return ret;
                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
                        ALLOC_INIT_ZVAL(op_free);
                        if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
                            ZVAL_LONG(result, 1);
                            zend_free_obj_get_result(op_free TSRMLS_CC);
                            return SUCCESS;
                        }
                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
                        zend_free_obj_get_result(op_free TSRMLS_CC);
                        return ret;
                    }
                }
                if (Z_TYPE_P(op2) == IS_OBJECT) {
                    if (Z_OBJ_HT_P(op2)->get) {
                        op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
                        ret = compare_function(result, op1, op_free TSRMLS_CC);
                        zend_free_obj_get_result(op_free TSRMLS_CC);
                        return ret;
                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
                        ALLOC_INIT_ZVAL(op_free);
                        if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
                            ZVAL_LONG(result, -1);
                            zend_free_obj_get_result(op_free TSRMLS_CC);
                            return SUCCESS;
                        }
                        ret = compare_function(result, op1, op_free TSRMLS_CC);
                        zend_free_obj_get_result(op_free TSRMLS_CC);
                        return ret;
                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
                        ZVAL_LONG(result, 1);
                        return SUCCESS;
                    }
                }
                if (!converted) {
                    if (Z_TYPE_P(op1) == IS_NULL) {
                        zendi_convert_to_boolean(op2, op2_copy, result);
                        ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
                        return SUCCESS;
                    } else if (Z_TYPE_P(op2) == IS_NULL) {
                        zendi_convert_to_boolean(op1, op1_copy, result);
                        ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
                        return SUCCESS;
                    } else if (Z_TYPE_P(op1) == IS_BOOL) {
                        zendi_convert_to_boolean(op2, op2_copy, result);
                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
                        return SUCCESS;
                    } else if (Z_TYPE_P(op2) == IS_BOOL) {
                        zendi_convert_to_boolean(op1, op1_copy, result);
                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
                        return SUCCESS;
                    } else {
                        zendi_convert_scalar_to_number(op1, op1_copy, result);
                        zendi_convert_scalar_to_number(op2, op2_copy, result);
                        converted = 1;
                    }
                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
                    ZVAL_LONG(result, 1);
                    return SUCCESS;
                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
                    ZVAL_LONG(result, -1);
                    return SUCCESS;
                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
                    ZVAL_LONG(result, 1);
                    return SUCCESS;
                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
                    ZVAL_LONG(result, -1);
                    return SUCCESS;
                } else {
                    ZVAL_LONG(result, 0);
                    return FAILURE;
                }
        }
    }
}
/* }}} */

zend/zend_operators.c:132行
字符串转换数字是,前面字符过滤规则


static inline zend_uchar is_numeric_string_ex(const char *str, int length, long *lval, double *dval, int allow_errors, int *oflow_info)
{
    const char *ptr;
    int base = 10, digits = 0, dp_or_e = 0;
    double local_dval;
    zend_uchar type;
 
    if (!length) {
        return 0;
    }
 
    if (oflow_info != NULL) {
        *oflow_info = 0;
    }
 
    /* Skip any whitespace
     * This is much faster than the isspace() function */
    while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
        str++;
        length--;
    }
    ptr = str;
 
    if (*ptr == '-' || *ptr == '+') {
        ptr++;
    }
 
    if (ZEND_IS_DIGIT(*ptr)) {
        /* Handle hex numbers
         * str is used instead of ptr to disallow signs and keep old behavior */
        if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
            base = 16;
            ptr += 2;
        }
 
        /* Skip any leading 0s */
        while (*ptr == '0') {
            ptr++;
        }
 
        /* Count the number of digits. If a decimal point/exponent is found,
         * it's a double. Otherwise, if there's a dval or no need to check for
         * a full match, stop when there are too many digits for a long */
        for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) {
check_digits:
            if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) {
                continue;
            } else if (base == 10) {
                if (*ptr == '.' && dp_or_e < 1) {
                    goto process_double;
                } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
                    const char *e = ptr + 1;
 
                    if (*e == '-' || *e == '+') {
                        ptr = e++;
                    }
                    if (ZEND_IS_DIGIT(*e)) {
                        goto process_double;
                    }
                }
            }
 
            break;
        }
 
        if (base == 10) {
            if (digits >= MAX_LENGTH_OF_LONG) {
                if (oflow_info != NULL) {
                    *oflow_info = *str == '-' ? -1 : 1;
                }
                dp_or_e = -1;
                goto process_double;
            }
        } else if (!(digits < SIZEOF_LONG * 2 || (digits == SIZEOF_LONG * 2 && ptr[-digits] <= '7'))) {
            if (dval) {
                local_dval = zend_hex_strtod(str, &ptr);
            }
            if (oflow_info != NULL) {
                *oflow_info = 1;
            }
            type = IS_DOUBLE;
        }
    } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
process_double:
        type = IS_DOUBLE;
 
        /* If there's a dval, do the conversion; else continue checking
         * the digits if we need to check for a full match */
        if (dval) {
            local_dval = zend_strtod(str, &ptr);
        } else if (allow_errors != 1 && dp_or_e != -1) {
            dp_or_e = (*ptr++ == '.') ? 1 : 2;
            goto check_digits;
        }
    } else {
        return 0;
    }
 
    if (ptr != str + length) {
        if (!allow_errors) {
            return 0;
        }
        if (allow_errors == -1) {
            zend_error(E_NOTICE, "A non well formed numeric value encountered");
        }
    }
 
    if (type == IS_LONG) {
        if (digits == MAX_LENGTH_OF_LONG - 1) {
            int cmp = strcmp(&ptr[-digits], long_min_digits);
 
            if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
                if (dval) {
                    *dval = zend_strtod(str, NULL);
                }
                if (oflow_info != NULL) {
                    *oflow_info = *str == '-' ? -1 : 1;
                }
 
                return IS_DOUBLE;
            }
        }
 
        if (lval) {
            *lval = strtol(str, NULL, base);
        }
 
        return IS_LONG;
    } else {
        if (dval) {
            *dval = local_dval;
        }
 
        return IS_DOUBLE;
    }
}


目录
相关文章
PHP为什么需要字符串运算?底层原理是什么?
PHP为什么需要字符串运算?底层原理是什么?
|
存储 PHP
为什么php的浮点数运算不准确
例子: //例子 $a = 10.601; $b = 10.6009; echo $a- $b; // 结果如下 0.00010000000000154 结果错误,why? why 根本原因, 在某些情况下, 2 进制无法精确表示 10 进制的小数部分。
1608 0
|
7月前
|
关系型数据库 MySQL PHP
PHP 原生操作 Mysql
PHP 原生操作 Mysql
81 0
|
7月前
|
关系型数据库 MySQL 数据库连接
PHP 原生连接 Mysql
PHP 原生连接 Mysql
107 0
|
7月前
|
关系型数据库 MySQL Unix
PHP MySql 安装与连接
PHP MySql 安装与连接
130 0
|
3月前
|
关系型数据库 MySQL PHP
|
9天前
|
PHP
web简易开发——通过php与HTML+css+mysql实现用户的登录,注册
web简易开发——通过php与HTML+css+mysql实现用户的登录,注册