PHP中將字符串轉(zhuǎn)化為整數(shù)(int) intval() printf() 性能測試
背景、概述
早在Sql注入橫行的前幾年,字符串轉(zhuǎn)化為整數(shù)就已經(jīng)被列為每個web程序必備的操作了。web程序?qū)et或post來的id、整數(shù)等值強(qiáng)制經(jīng)過轉(zhuǎn)化函數(shù)轉(zhuǎn)化為整數(shù),過濾掉危險字符,盡可能降低系統(tǒng)本身被Sql注入的可能性。
現(xiàn)如今,雖然Sql注入已經(jīng)逐漸淡出歷史舞臺,但是,為了保證web程序的正常運(yùn)行,減少出錯概率,更好的保證用的滿意度,我們同樣需要將用戶的不正確輸入轉(zhuǎn)化為我們所需要的。
轉(zhuǎn)化方式
在PHP中,我們可以使用3種方式將字符串轉(zhuǎn)化為整數(shù)。
1.強(qiáng)制類型轉(zhuǎn)換方式
強(qiáng)制類型轉(zhuǎn)換方式,就是“在要轉(zhuǎn)換的變量之前加上用括號括起來的目標(biāo)類型”(摘自PHP手冊“類型戲法”節(jié))的方式。
<?php $foo = "1"; // $foo 是字符串類型 $bar = (int)$foo; // $bar 是整型 ?>
對于整型來說,強(qiáng)制轉(zhuǎn)換類型名稱為int或者integer。
2.內(nèi)置函數(shù)方式
內(nèi)置函數(shù)方式,就是使用PHP的內(nèi)置函數(shù)intval進(jìn)行變量的轉(zhuǎn)換操作。
<?php $foo = "1"; // $foo 是字符串類型 $bar = intval($foo); // $bar 是整型 ?>
intval函數(shù)的格式為:
int intval(mixed $var [, int $base]); (摘自PHP手冊)
雖然PHP手冊中明確指出,intval()不能用于array和object的轉(zhuǎn)換。但是經(jīng)過我測試,轉(zhuǎn)換array的時候不會出任何問題,轉(zhuǎn)換值為1,而不是想象中的0??峙率且驗樵赑HP內(nèi)部,array類型的變量也被認(rèn)為是非零值得緣故吧。轉(zhuǎn)換object的時候,PHP會給出如下的 notice:
Object of class xxxx could not be converted to int in xxxxx.php on line xx
轉(zhuǎn)換值同樣為1。
3.格式化字符串方式
格式化字符串方式,是利用sprintf的%d格式化指定的變量,以達(dá)到類型轉(zhuǎn)換的目的。
<?php $foo = "1"; // $foo 是字符串類型 $bar = sprintf("%d", $foo); // $bar 是字符串類型 ?>
嚴(yán)格意義上講sprintf的轉(zhuǎn)換結(jié)果還是string型,因此它不應(yīng)該算是字符串轉(zhuǎn)化為整數(shù)的方式。但是經(jīng)過他處理之后的字符串值確實已經(jīng)成為了“被強(qiáng)制轉(zhuǎn)化為字符串類型的整數(shù)”。
實際測試
上面介紹了PHP中,將字符串轉(zhuǎn)化為整數(shù)的3種方式。對于一般的程序員來說,看到這里就算結(jié)束了,下面的部分是針對變態(tài)程序員的。
1.基本功能測試
設(shè)定以下數(shù)組:
<?php $a[] = "1"; $a[] = "a1"; $a[] = "1a"; $a[] = "1a2"; $a[] = "0"; $a[] = array('4',2); $a[] = "2.3"; $a[] = "-1"; $a[] = new Directory(); ?>
使用三種方式依次轉(zhuǎn)化上面給出的數(shù)組中的元素,查看轉(zhuǎn)換情況。程序源代碼如下:
<?php $a[] = "1"; $a[] = "a1"; $a[] = "1a"; $a[] = "1a2"; $a[] = "0"; $a[] = array('4',2); $a[] = "2.3"; $a[] = "-1"; $a[] = new Directory(); // int print "(int)<br />"; foreach($a as $v) { var_dump((int)$v); print "<br />"; } // intval print "intval();<br />"; foreach($a as $v) { var_dump(intval($v)); print "<br />"; } // sprintf print "sprintf();<br />"; foreach($a as $v) { var_dump(sprintf("%d", $v)); print "<br />"; } ?>
程序的最終運(yùn)行結(jié)果如下(已經(jīng)去掉轉(zhuǎn)換object時出現(xiàn)的notice):
(int)
int(1)
int(0)
int(1)
int(1)
int(0)
int(1)
int(2)
int(-1)
int(1)
intval();
int(1)
int(0)
int(1)
int(1)
int(0)
int(1)
int(2)
int(-1)
int(1)
sprintf();
string(1) "1"
string(1) "0"
string(1) "1"
string(1) "1"
string(1) "0"
string(1) "1"
string(1) "2"
string(2) "-1"
string(1) "1"
由此可以看出,三種轉(zhuǎn)換的結(jié)果是完全一樣的。那么從功能上講,3種方式都可以勝任轉(zhuǎn)換工作,那么接下來的工作就是看哪一種效率更高了。
2.性能測試
被測試字符串是我們在注入工作中可能會使用到的一種:
<?php $foo = "1';Select * ..."; ?>
獲取時間點的函數(shù)如下(用于獲取測試起始點和結(jié)束點,以計算消耗時間):
<?php ** * Simple function to replicate PHP 5 behaviour */ function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } ?>
?。ㄕ訮HP手冊microtime()函數(shù)節(jié))
測試過程是使用每種方式轉(zhuǎn)換變量$foo 1000000次(100萬次),并將各自的消耗時間輸出,總共進(jìn)行三組測試,盡可能降低誤差。測試程序如下:
<?php function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } $foo = "1';Select * ..."; // (int) $fStart = microtime_float(); for($i=0;$i<1000000;$i++) { $bar = (int)$foo; } $fEnd = microtime_float(); print "(int):" . ($fEnd - $fStart) . "s<br />"; // intval() $fStart = microtime_float(); for($i=0;$i<1000000;$i++) { $bar = intval($foo); } $fEnd = microtime_float(); print "intval():" . ($fEnd - $fStart) . "s<br />"; // sprintf() $fStart = microtime_float(); for($i=0;$i<1000000;$i++) { $bar = sprintf("%d", $foo); } $fEnd = microtime_float(); print "sprintf():" . ($fEnd - $fStart) . "s<br />"; ?>
最終的測試結(jié)果:
(int):0.67205619812012s
intval():1.1603000164032s
sprintf():2.1068270206451s
(int):0.66051411628723s
intval():1.1493890285492s
sprintf():2.1008238792419s
(int):0.66878795623779s
intval():1.1613430976868s
sprintf():2.0976209640503s
雖然這個測試有點變態(tài)(誰會連續(xù)轉(zhuǎn)換100w次的整數(shù)?),但是由此可以看出,使用強(qiáng)制類型轉(zhuǎn)換將字符串轉(zhuǎn)化為整數(shù)速度是最快的。
PHP中將字符串轉(zhuǎn)換為整數(shù)的最快方法
起步
這是個舊貼,在 SO 上偶然看到的:https://stackoverflow.com/questions/239136/fastest-way-to-convert-string-to-integer-in-php
對于 "123" => 123 最快的方法是什么,如果是 "hello" => ? 轉(zhuǎn)為整型又會有什么問題。
intval vs int
我以前是混著用的,有時用 intval($var)
有時用 (int) $var
,純看哪個順手。看了 SO 上才知道,顯式的類型轉(zhuǎn)換的性能大約是 intval
4 倍。這就可以是性能調(diào)優(yōu)的小 Tip 了。
我測了不同的 $val 值,發(fā)現(xiàn)兩者得到的結(jié)果完全一樣,發(fā)出的警告也是相同的。
因此在不考慮 intval
需要第二個參數(shù)的情況下,就可以放心的使用 int
來做轉(zhuǎn)換了。
深層原因
網(wǎng)友 Joseph Scott 對 OPCODE 進(jìn)行了分析,解釋了其深層原因
intval() 0 ASSIGN 1 SEND_VAR 2 DO_FCALL 3 ASSIGN 4 RETURN 5* ZEND_HANDLE_EXCEPTION int 0 ASSIGN 1 CAST 2 ASSIGN 3 RETURN 4* ZEND_HANDLE_EXCEPTION
SEND_VAR
和 DO_FCALL
操作,是導(dǎo)致 int
比 intval()
快很多的原因。
ps: 還有另一個類型轉(zhuǎn)換的 settype
就不用試了,它的性能比 intval
和 int
都差。
總結(jié)
使用強(qiáng)制類型轉(zhuǎn)換方式將字符串轉(zhuǎn)化為整數(shù)是最直接的轉(zhuǎn)化方式之一(可以直接獲得整型的變量值)。從代碼可讀性角度上講,sprintf方式代碼比較長,而且其結(jié)果有可能還需要再次進(jìn)行強(qiáng)制類型轉(zhuǎn)換,而intval函數(shù)是典型的面向過程式轉(zhuǎn)換,強(qiáng)制類型轉(zhuǎn)換則比較直接的將“我要轉(zhuǎn)化”這個思想傳遞給閱讀者。從效率上講,強(qiáng)制類型轉(zhuǎn)換方式也是最快速的轉(zhuǎn)化方式。因此,對于經(jīng)常進(jìn)行轉(zhuǎn)化工作的程序員,我推薦使用這種方式。
相關(guān)文章
PHP使用strrev翻轉(zhuǎn)中文亂碼問題的解決方法
這篇文章主要介紹了PHP使用strrev翻轉(zhuǎn)中文亂碼問題的解決方法,通過自定義函數(shù)遍歷字符串并設(shè)置編碼格式解決亂碼問題,需要的朋友可以參考下2017-01-01