今天遇到一個奇怪的問題
<?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")結束轉換,並將結果返回。