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 相关文章推荐
4.与数据库的连接
Oct 09 PHP
杏林同学录(九)
Oct 09 PHP
PHP生成excel时单元格内换行问题的解决方法
Aug 26 PHP
深入理解require与require_once与include以及include_once的区别
Jun 05 PHP
解析使用substr截取UTF-8中文字符串出现乱码的问题
Jun 20 PHP
教你如何快捷的使用cmd访问mysql小技巧
May 26 PHP
thinkphp模板赋值与替换实例简述
Nov 24 PHP
php利用反射实现插件机制的方法
Mar 14 PHP
PHP+redis实现添加处理投票的方法
Nov 14 PHP
简单介绍PHP非阻塞模式
Mar 03 PHP
PHP面试常用算法(推荐)
Jul 22 PHP
php大小写转换函数(strtolower、strtoupper)用法介绍
Nov 17 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 date与gmdate的获取日期的区别
2010/02/08 PHP
php下批量挂马和批量清马代码
2011/02/27 PHP
PHP读取文件内容的五种方式
2015/12/28 PHP
PHP 结合 Boostrap 结合 js 实现学生列表删除编辑及搜索功能
2019/05/21 PHP
Thinkphp5.0框架视图view的循环标签用法示例
2019/10/12 PHP
jQuery 学习入门篇附实例代码
2010/03/16 Javascript
JS的千分位算法实现思路
2013/07/31 Javascript
jquery.mousewheel实现整屏翻屏效果
2015/08/30 Javascript
JS搜狐面试题分析
2016/12/16 Javascript
Vue.js学习笔记之常用模板语法详解
2017/07/25 Javascript
详解vue 模拟后台数据(加载本地json文件)调试
2017/08/25 Javascript
angularJS实现不同视图同步刷新详解
2018/10/09 Javascript
如何安装控制器JavaScript生成插件详解
2018/10/21 Javascript
微信小程序实现联动选择器
2019/02/15 Javascript
Vue 事件处理操作实例详解
2019/03/05 Javascript
vue render函数动态加载img的src路径操作
2020/10/26 Javascript
使用js原生实现年份轮播选择效果实例
2021/01/12 Javascript
Python程序中使用SQLAlchemy时出现乱码的解决方案
2015/04/24 Python
深入理解Python中命名空间的查找规则LEGB
2015/08/06 Python
基于Django的python验证码(实例讲解)
2017/10/23 Python
Django admin实现图书管理系统菜鸟级教程完整实例
2017/12/12 Python
python2.6.6如何升级到python2.7.14
2018/04/08 Python
ubuntu系统下使用pm2设置nodejs开机自启动的方法
2018/05/12 NodeJs
pygame游戏之旅 游戏中添加显示文字
2018/11/20 Python
Python文件打开方式实例详解【a、a+、r+、w+区别】
2019/03/30 Python
python列表,字典,元组简单用法示例
2019/07/11 Python
HTML5本地存储和本地数据库实例详解
2017/09/05 HTML / CSS
沙特阿拉伯网上购物:Sayidaty Mall
2018/05/06 全球购物
教师找工作推荐信
2013/11/23 职场文书
制药工程专业个人求职自荐信
2014/01/25 职场文书
法制宣传月活动方案
2014/05/11 职场文书
北京故宫的导游词
2015/01/31 职场文书
实习护士自荐信
2015/03/25 职场文书
2015年政治教研组工作总结
2015/07/22 职场文书
MySQL的InnoDB存储引擎的数据页结构详解
2022/03/03 MySQL
TypeScript 内置高级类型编程示例
2022/09/23 Javascript