Press "Enter" to skip to content

PHP字符串比较

我们在代码中用的最多的逻辑是什么?
你知道如下的几段代码的布尔结果分别是什么么?

var_dump("1" == "1e0");
var_dump("1" == "0x1");
var_dump("20" == "2e1");
var_dump("10" == "  0x0a");

等等;
对, 也许你会说在PHP手册的附录中有一部分关于这个问题的总结. 问题是,这只是知其然, 那么所以然是什么呢?
今天就有一个网友问了我一个问题:

	var_dump("1" == "1e0");  //true
	var_dump("1" == "1ef"); //false
    这两个的结果为什么不一样啊.

也就是说, 上面的等式a要成立, 那么唯一的解释就是PHP讲他们双发都当作int来比较.
但是, var_dump("1e0"),或者var_dump("1"),都是string啊.
那么, 到底PHP是怎么决定相比较的俩者的类型的呢?
还是老办法, 先从zend_language_scanner.l中找到==的opcode码 结果是T_IS_EQUAL
然后在zend_language_parse.y中找到编译器看到T_IS_EQUAL会做什么:

	 expr T_IS_EQUAL expr            { zend_do_binary_op(ZEND_IS_EQUAL, &$$, &$1, &$3 TSRMLS_CC); }

那么接下就去zend_vm_def.h中寻找当ZE遇到ZEND_IS_EQUAL会做什么:

	ZEND_VM_HANDLER(17, ZEND_IS_EQUAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)
	{
		zend_op *opline = EX(opline);
		zend_free_op free_op1, free_op2;
		is_equal_function(&EX_T(opline->result.u.var).tmp_var,
			GET_OP1_ZVAL_PTR(BP_VAR_R),
			GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC);
		FREE_OP1();
		FREE_OP2();
		ZEND_VM_NEXT_OPCODE();
	}

看来,所有"=="判断都是由is_equal_function完成的, 让我们一起再看看它是什么样的:

	ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
	{
		if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
			return FAILURE;
		}
		convert_to_boolean(result);
		if (result->value.lval == 0) {
			result->value.lval = 1;
		} else {
			result->value.lval = 0;
		}
		return SUCCESS;
	}

哦, 看来不是, 还要进一步查看compare_function
代码太长, 不贴了. 在compare_function中, 当俩个比较操作数都是string的时候,会调用zendi_smart_strcmp:

    if (op1->type == IS_STRING && op2->type == IS_STRING) {
        zendi_smart_strcmp(result, op1, op2);
        COMPARE_RETURN_AND_FREE(SUCCESS);
    }

而在zendi_smart_strcmp中, 对于俩个字符串, 会首先判断他们是否是numeric_string, 如果是,那么就会转换成整形来比较..
那么什么是numeric string呢? 因为PHP不区分类型, 所以她采用一个策略, 当你的变量看起来是一个数字的时候, 那么她就认为这个变量是一个数字. 简单来说, numeric_string就是表示数字的字符串:
也就是说,如下的比较结果都是真:

	var_dump("1" == "1e0");
	var_dump("1" == "0x1");
	var_dump("20" == "2e1");
	var_dump("10" == "  0x0a");

呵呵, 读者们遇到过这个问题的困扰么?
ps: 谢谢bingxuefenggu网友的问题.

11 Comments

  1. maoshen
    maoshen March 6, 2018

    在PHP7.0.21中,有问题,
    var_dump(“1” == hexdec(“0x1”));//true
    var_dump(“1” == (“0x1”));//false
    var_dump(“0x1” + 1);//int(1)
    var_dump(“10″ == hexdec(” 0x0a”));//true
    var_dump(“10″ == (” 0x0a”));//false
    var_dump(” 0x0a” +1);//int(1)
    但是在5.6.31,5.3.29中,都是true

  2. Earl Askvig
    Earl Askvig June 20, 2014

    Good day every person. We’re glad to be in this article with you all.

  3. 清水河和尚
    清水河和尚 September 18, 2012

    竟然把八进制当做八进制的。
    while (*ptr == ‘0’) {
    ptr++;
    }

  4. 雪候鸟
    雪候鸟 October 26, 2011

    @何林丹 科学计数表示

  5. 何林丹
    何林丹 October 26, 2011

    您好,第三个表达式有些不明白
    var_dump(“20” == “2e1”);
    php是怎么把字符串”2e1″转换成了整数呢,我感觉应该是2,而不是20,希望你能答疑一下

  6. zvaly
    zvaly February 26, 2009

    我还真是佩服你的思维,能在复杂的代码里随处逛,不会走丢,呵呵。最近在做什么有意思的东西吗?

    • laruence
      laruence March 1, 2009

      @zvaly, 最近在基于Extjs做一个mis系统, 呵呵, 现在代码量已经7w了….

  7. zvaly
    zvaly February 23, 2009

    终于发新文章了,还不错,但最近就这些进步吗?

    • 雪候鸟
      雪候鸟 February 24, 2009

      @zvaly, 呵呵, 最近项目紧的很, 项目管理方面, 烦心事更多…

Comments are closed.