PHP匿点之string转int

今天遇到一个奇怪的问题

<?php
echo 1 + 2 + "3+4+5";

输出的结果为6; 当时有点想不通,1+2=3是没问题的  但是 3+“3+4+5” = 6 是为什么呢, 百思不得其解。所以我们还是从内核来看吧。

我们先看下opcode:


这里的 “3+4+5”被编译成3%2B4%2B5,以字符串形式存在,与整形相加,需要先转为整形,想到整形我们就intval()函数,那么我们就借助intval函数去找点启发吧

/* {{{ proto int intval(mixed var [, int base])
   Get the integer value of a variable using the optional base for the conversion */
PHP_FUNCTION(intval)
{
	zval **num;
	long arg_base;
	int base;

	switch (ZEND_NUM_ARGS()) {
		case 1:
			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &num) == FAILURE) {
				return;
			}
			base = 10;
			break;

		case 2:
			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &num, &arg_base) == FAILURE) {
				return;
			}
			base = arg_base;
			break;

		default:
			WRONG_PARAM_COUNT;
	}

	RETVAL_ZVAL(*num, 1, 0);					//设置返回值给 return_value
	convert_to_long_base(return_value, base);	//根据base进制进行转换
}
/* }}} */
可以看出 问题的关键就在convert_to_long_base上,接上这个convert_to_long_base往下看

ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */
{
....省略若干....
		case IS_STRING:
			{
				char *strval = Z_STRVAL_P(op);				//获取op的string值作为指针返回给char类型的指针变量

				Z_LVAL_P(op) = strtol(strval, NULL, base);	//通过strtol函数把char类型指针变量转为long
				STR_FREE(strval);							//释放这个char类型的指针变量
			}
			break;
....省略若干....
        Z_TYPE_P(op) = IS_LONG;
}
/* }}} */

哦了, 看来问题就出在这个strtol上, 我们来看看这个strol到底偷偷摸摸的对string做了什么

我们先来看看strol的作用

相关函数: atof, atoi, atol, strtod, strtoul
表头文件: #include <stdlib.h>
定义函数: long int strtol(const char *nptr, char **endptr, int base)
函数说明: strtol()会将参数nptr字符串根据参数base来转换成长整型数。参数base范围从2至36,或0。参数base代表采用的进制方式,如base值为10则采用10进制(字符串以10进制表示),若base值为16则采用16进制(字符串以16进制表示)。当base值为0时则是采用10进制做转换,但遇到如''0x''前置字符则会使用16进制做转换。<span style="color:#3366ff;">一开始strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时(''\0'')结束转换,并将结果返回。</span>
若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回。
返回值:    返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中。
附加说明: ERANGE指定的转换字符串超出合法范围。


一开始strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时(''\0'')结束转换,并将结果返回。


char buffer[20]="10379cend$3";
char *stop;
printf("%d\n",strtol(buffer, &stop, 10));
printf("%s\n", stop);
输出结果:
10379
cend$3

于是乎,我们明白了一切,“3%2B4%2B5” 最终出来的 3。


为了验证我们的猜想,我们来看看

<?php
echo 1 + 2 + "-5+6+7";
结果是不是-2呢?见证时刻到了,运行下, 结果果然是-2.


所以以后我们再遇到string转int时候就不要迷惑了。记得跳过空格,知道遇到数字或者正负号才开始转换,再遇到非数字或字符串结束时("\0")结束转换,并将结果返回。


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页