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")結束轉換,並將結果返回。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章