1. 程式人生 > >PHP中將字串轉化為整數(int) intval() printf() 效能測試

PHP中將字串轉化為整數(int) intval() printf() 效能測試

背景、概述 
  早在Sql注入橫行的前幾年,字串轉化為整數就已經被列為每個web程式必備的操作了。web程式將get或post來的id、整數等值強制經過轉化函式轉化為整數,過濾掉危險字元,儘可能降低系統本身被Sql注入的可能性。 
  現如今,雖然Sql注入已經逐漸淡出歷史舞臺,但是,為了保證web程式的正常執行,減少出錯概率,更好的保證用的滿意度,我們同樣需要將使用者的不正確輸入轉化為我們所需要的。 
轉化方式 
  在PHP中,我們可以使用3種方式將字串轉化為整數。 
1.強制型別轉換方式 
  強制型別轉換方式,就是“在要轉換的變數之前加上用括號括起來的目標型別”(摘自PHP手冊“型別戲法”節)的方式。 
複製程式碼
程式碼如下:
<?php 
$foo = "1"; // $foo 是字串型別 
$bar = (int)$foo; // $bar 是整型 
?> 

  對於整型來說,強制轉換型別名稱為int或者integer。 
2.內建函式方式 
  內建函式方式,就是使用PHP的內建函式intval進行變數的轉換操作。 
複製程式碼程式碼如下:
<?php 
$foo = "1"; // $foo 是字串型別 
$bar = intval($foo); // $bar 是整型 
?> 

  intval函式的格式為: 
  int intval(mixed $var [, int $base]); (摘自PHP手冊) 
  雖然PHP手冊中明確指出,intval()不能用於array和object的轉換。但是經過我測試,轉換array的時候不會出任何問題,轉換值為1,而不是想象中的0。恐怕是因為在PHP內部,array型別的變數也被認為是非零值得緣故吧。轉換object的時候,PHP會給出如下的 notice: 
  Object of class xxxx could not be converted to int in xxxxx.php on line xx 
  轉換值同樣為1。 
3.格式化字串方式
 
  格式化字串方式,是利用sprintf的%d格式化指定的變數,以達到型別轉換的目的。 
複製程式碼程式碼如下:
<?php 
$foo = "1"; // $foo 是字串型別 
$bar = sprintf("%d", $foo); // $bar 是字串型別 
?> 

  嚴格意義上講sprintf的轉換結果還是string型,因此它不應該算是字串轉化為整數的方式。但是經過他處理之後的字串值確實已經成為了“被強制轉化為字串型別的整數”。 
實際測試 
  上面介紹了PHP中,將字串轉化為整數的3種方式。對於一般的程式設計師來說,看到這裡就算結束了,下面的部分是針對變態程式設計師的。 
1.基本功能測試 
  設定以下陣列: 
複製程式碼程式碼如下:
<?php 
$a[] = "1"; 
$a[] = "a1"; 
$a[] = "1a"; 
$a[] = "1a2"; 
$a[] = "0"; 
$a[] = array('4',2); 
$a[] = "2.3"; 
$a[] = "-1"; 
$a[] = new Directory(); 
?> 

  使用三種方式依次轉化上面給出的陣列中的元素,檢視轉換情況。程式原始碼如下: 
複製程式碼程式碼如下:
<?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 />"; 

?> 

  程式的最終執行結果如下(已經去掉轉換object時出現的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" 
  由此可以看出,三種轉換的結果是完全一樣的。那麼從功能上講,3種方式都可以勝任轉換工作,那麼接下來的工作就是看哪一種效率更高了。 
2.效能測試 
  被測試字串是我們在注入工作中可能會使用到的一種: 
複製程式碼程式碼如下:
<?php 
$foo = "1';Select * ..."; 
?> 
  獲取時間點的函式如下(用於獲取測試起始點和結束點,以計算消耗時間): 

<?php 
** 
* Simple function to replicate PHP 5 behaviour 
*/ 
function microtime_float() 

list($usec, $sec) = explode(" ", microtime()); 
return ((float)$usec + (float)$sec); 

?> 

  (摘自PHP手冊microtime()函式節) 
  測試過程是使用每種方式轉換變數$foo 1000000次(100萬次),並將各自的消耗時間輸出,總共進行三組測試,儘可能降低誤差。測試程式如下: 
複製程式碼程式碼如下:
<?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 />"; 
?> 

  最終的測試結果: 
(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 

  雖然這個測試有點變態(誰會連續轉換100w次的整數?),但是由此可以看出,使用強制型別轉換將字串轉化為整數速度是最快的。 
總結 
  使用強制型別轉換方式將字串轉化為整數是最直接的轉化方式之一(可以直接獲得整型的變數值)。從程式碼可讀性角度上講,sprintf方式程式碼比較長,而且其結果有可能還需要再次進行強制型別轉換,而intval函式是典型的面向過程式轉換,強制型別轉換則比較直接的將“我要轉化”這個思想傳遞給閱讀者。從效率上講,強制型別轉換方式也是最快速的轉化方式。因此,對於經常進行轉化工作的程式設計師,我推薦使用這種方式。