PHP中将字符串转化为整数(int) intval() printf() 性能测试


Posted in PHP onMarch 20, 2020

背景、概述

早在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次的整数?),但是由此可以看出,使用强制类型转换将字符串转化为整数速度是最快的。

PHP中将字符串转换为整数的最快方法

起步

这是个旧贴,在 SO 上偶然看到的:https://stackoverflow.com/questions/239136/fastest-way-to-convert-string-to-integer-in-php

对于 "123" => 123 最快的方法是什么,如果是 "hello" => ? 转为整型又会有什么问题。

intval vs int

我以前是混着用的,有时用 intval($var) 有时用 (int) $var ,纯看哪个顺手。看了 SO 上才知道,显式的类型转换的性能大约是 intval 4 倍。这就可以是性能调优的小 Tip 了。

我测了不同的 $val 值,发现两者得到的结果完全一样,发出的警告也是相同的。

因此在不考虑 intval 需要第二个参数的情况下,就可以放心的使用 int 来做转换了。

深层原因

网友 Joseph Scott 对 OPCODE 进行了分析,解释了其深层原因

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_VARDO_FCALL 操作,是导致 int intval() 快很多的原因。

ps: 还有另一个类型转换的 settype 就不用试了,它的性能比 intval int 都差。

总结

使用强制类型转换方式将字符串转化为整数是最直接的转化方式之一(可以直接获得整型的变量值)。从代码可读性角度上讲,sprintf方式代码比较长,而且其结果有可能还需要再次进行强制类型转换,而intval函数是典型的面向过程式转换,强制类型转换则比较直接的将“我要转化”这个思想传递给阅读者。从效率上讲,强制类型转换方式也是最快速的转化方式。因此,对于经常进行转化工作的程序员,我推荐使用这种方式。

PHP 相关文章推荐
用PHP连接Oracle数据库
Oct 09 PHP
php面向对象全攻略 (五) 封装性
Sep 30 PHP
如何解决CI框架的Disallowed Key Characters错误提示
Jul 05 PHP
ThinkPHP3.1新特性之多数据库操作更加完善
Jun 19 PHP
Discuz批量替换帖子内容的方法(使用SQL更新数据库)
Jun 23 PHP
PHP中的命名空间相关概念浅析
Jan 22 PHP
php检测文本的编码
Jul 26 PHP
详解php中反射的应用
Mar 15 PHP
PHP GD库相关图像生成和处理函数小结
Sep 30 PHP
Laravel 关联模型-关联新增和关联更新的方法
Oct 10 PHP
PHP实现基本留言板功能原理与步骤详解
Mar 26 PHP
thinkphp诸多限制条件下如何getshell详解
Dec 09 PHP
PHP中文件读、写、删的操作(PHP中对文件和目录操作)
Mar 06 #PHP
PHP运行出现Notice : Use of undefined constant 的完美解决方案分享
Mar 05 #PHP
php在服务器执行exec命令失败的解决方法
Mar 03 #PHP
Php Ctemplate引擎开发相关内容
Mar 03 #PHP
PHP代码网站如何防范SQL注入漏洞攻击建议分享
Mar 01 #PHP
PHP和JAVA中的重载(overload)和覆盖(override) 介绍
Mar 01 #PHP
JS中encodeURIComponent函数用php解码的代码
Mar 01 #PHP
You might like
smarty section简介与用法分析
2008/10/03 PHP
《PHP编程最快明白》第四讲:日期、表单接收、session、cookie
2010/11/01 PHP
PHP使用内置dir类实现目录遍历删除
2015/03/31 PHP
PHP判断FORM表单或URL参数来的数据是否为整数的方法
2016/03/25 PHP
php读取torrent种子文件内容的方法(测试可用)
2016/05/03 PHP
php使用ffmpeg向视频中添加文字字幕的实现方法
2016/05/23 PHP
PHP getName()函数讲解
2019/02/03 PHP
js变量作用域及可访问性的探讨
2006/11/23 Javascript
解决jQuery插件tipswindown与hintbox冲突
2010/11/05 Javascript
jquery miniui 教程 表格控件 合并单元格应用
2012/11/25 Javascript
jQuery获取样式中的背景颜色属性值/颜色值
2012/12/17 Javascript
node.js中的fs.rmdir方法使用说明
2014/12/16 Javascript
javascript批量修改文件编码格式的方法
2015/01/27 Javascript
JavaScript事件 &quot;事件对象&quot;的注意要点
2016/01/14 Javascript
用JS中split方法实现彩色文字背景效果实例
2016/08/24 Javascript
js方法数据验证的简单实例
2016/09/17 Javascript
AngularJS ng-repeat数组有重复值的解决方法
2016/10/23 Javascript
JavaScript计算值然后把值嵌入到html中的实现方法
2016/10/29 Javascript
js封装成插件的步骤方法
2017/09/11 Javascript
微信小程序实现漂亮的弹窗效果
2020/05/26 Javascript
Vue多组件仓库开发与发布详解
2019/02/28 Javascript
[jQuery] 事件和动画详解
2019/03/05 jQuery
[50:04]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第二局
2016/02/28 DOTA
[40:01]OG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python3 图片referer防盗链的实现方法
2018/03/12 Python
python逆序打印各位数字的方法
2018/06/25 Python
Django 自动生成api接口文档教程
2019/11/19 Python
Python脚本去除文件的只读性操作
2020/03/05 Python
keras中epoch,batch,loss,val_loss用法说明
2020/07/02 Python
简单的HTML5初步入门教程
2015/09/29 HTML / CSS
匡威爱尔兰官网:Converse爱尔兰
2019/06/09 全球购物
捷克家具销售网站:SCONTO Nábytek
2020/01/02 全球购物
大专应届生个人简历的自我评价
2013/10/15 职场文书
发票退票证明
2015/06/24 职场文书
教师培训学习心得体会
2016/01/21 职场文书
Python使用永中文档转换服务
2022/05/06 Python