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 相关文章推荐
用Flash图形化数据(二)
Oct 09 PHP
PHP读取目录下所有文件的代码
Jan 07 PHP
PHP为表单获取的URL 地址预设 http 字符串函数代码
May 26 PHP
php文章内容分页并生成相应的htm静态页面代码
Jun 07 PHP
PHP取得一个类的属性和方法的实现代码
May 22 PHP
openflashchart 2.0 简单案例php版
May 21 PHP
WordPress中注册菜单与调用菜单的方法详解
Dec 18 PHP
php简单实现多语言切换的方法
May 09 PHP
php+ajax注册实时验证功能
Jul 20 PHP
创建无限极分类树型结构的简单方法
Jun 20 PHP
Laravel框架中自定义模板指令总结
Dec 17 PHP
laravel 解决Validator使用中出现的问题
Oct 25 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
也谈截取首页新闻 - 范例
2006/10/09 PHP
PHP提示Deprecated: mysql_connect(): The mysql extension is deprecated的解决方法
2014/08/28 PHP
php获取json数据所有的节点路径
2015/05/17 PHP
php通过执行CutyCapt命令实现网页截图的方法
2016/09/30 PHP
PHP编程实现阳历转换为阴历的方法实例
2017/08/08 PHP
PHP使用ActiveMQ实例
2018/02/05 PHP
浅析tr的隐藏和显示问题
2014/03/05 Javascript
兼容主流浏览器的jQuery+CSS 实现遮罩层的简单代码
2014/10/14 Javascript
JavaScript操作URL的相关内容集锦
2015/10/29 Javascript
深入理解jQuery中的事件冒泡
2016/05/24 Javascript
jquery做个日期选择适用于手机端示例
2017/01/10 Javascript
完美解决UI-Grid表格元素中多个空格显示为一个空格的问题
2017/04/25 Javascript
详解jquery选择器的原理
2017/08/01 jQuery
node.js+captchapng+jsonwebtoken实现登录验证示例
2017/08/17 Javascript
微信小程序开发之IOS和Android兼容的问题
2017/09/26 Javascript
浅谈vue-cli 3.0.x 初体验
2018/04/11 Javascript
node.js利用socket.io实现多人在线匹配联机五子棋
2018/05/31 Javascript
vue自定义tap指令及tap事件的实现
2018/09/18 Javascript
微信小程序 wepy框架与iview-weapp的用法详解
2019/04/10 Javascript
Jquery让form表单异步提交代码实现
2019/11/14 jQuery
vue 路由meta 设置导航隐藏与显示功能的示例代码
2020/09/04 Javascript
vue基于Echarts的拖拽数据可视化功能实现
2020/12/04 Vue.js
python3生成随机数实例
2014/10/20 Python
使用Python脚本生成随机IP的简单方法
2015/07/30 Python
详解Python中的from..import绝对导入语句
2016/06/21 Python
python 实现提取某个索引中某个时间段的数据方法
2019/02/01 Python
python使用time、datetime返回工作日列表实例代码
2019/05/09 Python
python爬虫 urllib模块发起post请求过程解析
2019/08/20 Python
python实现异常信息堆栈输出到日志文件
2019/12/26 Python
美国演唱会和体育门票购买网站:Ticketnetwork
2018/10/19 全球购物
美国尼曼百货官网:Neiman Marcus
2019/09/05 全球购物
失业者真诚求职信范文
2013/12/25 职场文书
学习焦裕禄观后感
2015/06/09 职场文书
会议营销主持词
2015/07/03 职场文书
Java基础——Map集合
2022/04/01 Java/Android
win11无线投屏在哪设置? win11无线投屏功能的使用方法
2022/04/08 数码科技