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+Tidy-完美的XHTML纠错+过滤
Apr 10 PHP
php中对xml读取的相关函数的介绍一
Jun 05 PHP
php print EOF实现方法
May 21 PHP
PHP中json_encode、json_decode与serialize、unserialize的性能测试分析
Jun 09 PHP
PHP超级全局变量数组小结
Oct 04 PHP
php使用反射插入对象示例分享
Mar 11 PHP
php以post形式发送xml的方法
Nov 04 PHP
php删除文本文件中重复行的方法
Apr 28 PHP
PHP函数实现从一个文本字符串中提取关键字的方法
Jul 01 PHP
PHP+jquery+CSS制作头像登录窗(仿QQ登陆)
Oct 20 PHP
PHP仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(上)
May 26 PHP
PHP defined()函数的使用图文详解
Jul 20 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
PHP中的串行化变量和序列化对象
2006/09/05 PHP
解析argc argv在php中的应用
2013/06/24 PHP
php获取当月最后一天函数分享
2015/02/02 PHP
php array_multisort 对数组进行排序详解及实例代码
2016/10/27 PHP
ThinkPHP3.2.3框架邮件发送功能图文实例详解
2019/04/23 PHP
Yii框架学习笔记之session与cookie简单操作示例
2019/04/30 PHP
一个基于jQuery的树型插件(OrangeTree)使用介绍
2012/05/03 Javascript
jQuery中$.fn的用法示例介绍
2013/11/05 Javascript
Javascript玩转继承(三)
2014/05/08 Javascript
DOM 事件流详解
2015/01/20 Javascript
2种jQuery 实现刮刮卡效果
2015/02/01 Javascript
js实现简单的左右两边固定广告效果实例
2015/04/10 Javascript
js事件源window.event.srcElement兼容性写法(详解)
2016/11/25 Javascript
从零开始学习Node.js系列教程一:http get和post用法分析
2017/04/13 Javascript
ES6新特性二:Iterator(遍历器)和for-of循环详解
2017/04/20 Javascript
AngularJS自定义表单验证功能实例详解
2018/08/24 Javascript
layui实现根据table数据判断按钮显示情况的方法
2019/09/26 Javascript
vue输入框使用模糊搜索功能的实现代码
2020/05/26 Javascript
js+css3实现炫酷时钟
2020/08/18 Javascript
详解javascript脚本何时会被执行
2021/02/05 Javascript
[01:34]完美“圣”典宣传片震撼发布,12.17与你不见不散
2016/12/16 DOTA
python实现sublime3的less编译插件示例
2014/04/27 Python
Python实现数据库编程方法详解
2015/06/09 Python
python安装与使用redis的方法
2016/04/19 Python
mysql 之通过配置文件链接数据库
2017/08/12 Python
python下载文件记录黑名单的实现代码
2017/10/24 Python
PyCharm鼠标右键不显示Run unittest的解决方法
2018/11/30 Python
浅析Python 序列化与反序列化
2020/08/05 Python
python 爬取小说并下载的示例
2020/12/07 Python
Python命令行参数argv和argparse该如何使用
2021/02/08 Python
日本必酷网络直营店:Biccamera
2019/03/23 全球购物
Seavenger官网:潜水服、浮潜、靴子和袜子
2020/03/05 全球购物
优秀乡村医生事迹材料
2014/05/28 职场文书
公司放假通知范文
2015/04/14 职场文书
MySQL大小写敏感的注意事项
2021/05/24 MySQL
使用numpy实现矩阵的翻转(flip)与旋转
2021/06/03 Python