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 相关文章推荐
用ADODB来让PHP操作ACCESS数据库的方法
Dec 31 PHP
PHP 危险函数全解析
Sep 09 PHP
如何用php获取文件名后缀
Jun 09 PHP
php进行支付宝开发中return_url和notify_url的区别分析
Dec 22 PHP
php实现只保留mysql中最新1000条记录
Jun 18 PHP
Linux系统递归生成目录中文件的md5的方法
Jun 29 PHP
带你了解PHP7 性能翻倍的关键
Nov 19 PHP
php获取图片信息的方法详解
Dec 10 PHP
PHP导出Excel实例讲解
Jan 24 PHP
深入理解PHP 数组之count 函数
Jun 13 PHP
PHP5.4起内置web服务器使用方法
Aug 09 PHP
Laravel 5+ .env环境配置文件详解
Apr 06 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
Windows下IIS6/Apache2.2.4+MySQL5.2+PHP5.2.1安装配置方法
2007/05/03 PHP
PHP register_shutdown_function函数的深入解析
2013/06/03 PHP
PHP中使用substr()截取字符串出现中文乱码问题该怎么办
2015/10/21 PHP
PHP判断手机是IOS还是Android
2015/12/09 PHP
js禁止document element对象选中文本实现代码
2013/03/21 Javascript
jQuery 借助插件Lavalamp实现导航条动态美化效果
2013/09/27 Javascript
对象题目的一个坑 理解Javascript对象
2015/12/22 Javascript
javascript仿京东导航左侧分类导航下拉菜单效果
2020/11/25 Javascript
利用Node.js制作爬取大众点评的爬虫
2016/09/22 Javascript
微信小程序与php 实现微信支付的简单实例
2017/06/23 Javascript
javascript用rem来做响应式开发
2018/01/13 Javascript
JS实现判断有效的数独算法示例
2019/02/25 Javascript
layui将table转化表单显示的方法(即table.render转为表单展示)
2019/09/24 Javascript
vue element upload组件 file-list的动态绑定实现
2019/10/11 Javascript
vue-cli或vue项目利用HBuilder打包成移动端app操作
2020/07/29 Javascript
vue打开新窗口并实现传参的图文实例
2021/03/04 Vue.js
[37:45]完美世界DOTA2联赛PWL S3 LBZS vs Phoenix 第二场 12.09
2020/12/11 DOTA
Django中处理出错页面的方法
2015/07/15 Python
python中Matplotlib实现绘制3D图的示例代码
2017/09/04 Python
python3对接mysql数据库实例详解
2019/04/30 Python
python 一个figure上显示多个图像的实例
2019/07/08 Python
python numpy--数组的组合和分割实例
2020/02/24 Python
一文解决django 2.2与mysql兼容性问题
2020/07/15 Python
Philosophy美国官网:美国美容品牌
2016/08/15 全球购物
英国索普公园票务和酒店套餐:Thorpe Breaks
2019/09/14 全球购物
体育教育专业自荐信范文
2013/12/20 职场文书
中考冲刺决心书
2014/03/11 职场文书
档案工作汇报材料
2014/08/21 职场文书
竞选学习委员演讲稿
2014/09/01 职场文书
说谎欺骗人检讨书300字
2014/11/18 职场文书
新教师2015年度工作总结
2015/07/22 职场文书
老舍《猫》教学反思
2016/02/17 职场文书
Redis5之后版本的高可用集群搭建的实现
2021/04/27 Redis
基于HTML十秒做出淘宝页面
2021/10/24 HTML / CSS
浅谈css实现背景颜色半透明的两种方法
2021/12/06 HTML / CSS
SQL Server中使用表变量和临时表
2022/05/20 SQL Server