CrispDev
<< Back
『翻译』PHP 强制转换 vs. intval

原文信息

Original Post: PHP: Casting vs. intval()

By Hakre, hakre.wordpress.com, May 13th, 2010

Translated by Crisp

正文

在 PHP 中,使用 (int)$var 方式进行类型转换比使用 intval($var) 函数方式快 400% 到 650%。

运行测试

(int)$val vs. intval($val) 速度对比[系统 #1]

# 输入 (INT)$val INTVAL($val) 比率
#0 42 : 0.068180 / 0.448819 658%
#1 -42 : 0.067972 / 0.448907 660%
#2 4.2 : 0.072348 / 0.450288 622%
#3 ‘42’ : 0.087305 / 0.469350 537%
#4 ‘+42’ : 0.087590 / 0.471153 537%
#5 ‘-42’ : 0.089154 / 0.469826 526%
#6 34 : 0.068234 / 0.451035 661%
#7 ‘042’ : 0.089344 / 0.470391 526%
#8 0x1A : 0.072989 / 0.451909 619%
#9 ‘1e10’ : 0.088196 / 0.469347 532%
#10 26 : 0.068378 / 0.449884 657%
#11 42000000 : 0.068770 / 0.449416 653%
#12 2147483647 : 0.068927 / 0.448028 650%
#13 2147483648 : 0.072599 / 0.450618 620%
#14 4.2E+20 : 0.086305 / 0.467347 541%
#15 ‘420000000000000000000’ : 0.102120 / 0.484245 474%
#16 array() : 0.092310 / 0.472185 511%
#17 array(‘foo’, ‘bar’) : 0.112644 / 0.494482 438%

(int)$val vs. intval($val) 速度对比[系统 #2]

# 输入 (INT)$val INTVAL($val) 比率
#0 42 : 0.045576 / 0.194759 427%
#1 -42 : 0.042457 / 0.194273 457%
#2 4.2 : 0.047853 / 0.196049 409%
#3 ‘42’ : 0.055792 / 0.209531 375%
#4 ‘+42’ : 0.055158 / 0.208236 377%
#5 ‘-42’ : 0.056604 / 0.209486 370%
#6 34 : 0.042580 / 0.194606 457%
#7 ‘042’ : 0.056834 / 0.209276 368%
#8 0x1A : 0.045320 / 0.196626 433%
#9 ‘1e10’ : 0.054923 / 0.209295 381%
#10 26 : 0.042582 / 0.195295 458%
#11 42000000 : 0.042673 / 0.194469 455%
#12 2147483647 : 0.042560 / 0.194363 456%
#13 2147483648 : 0.045553 / 0.197149 432%
#14 4.2E+20 : 0.054069 / 0.206131 381%
#15 ‘420000000000000000000’ : 0.066170 / 0.218996 330%
#16 array() : 0.057587 / 0.210010 364%
#17 array(‘foo’, ‘bar’) : 0.071908 / 0.224338 311%

这组测试每个项目进行了 100000 次循环。两个测试都在 Windows 上运行。系统 #1 使用的是 PHP 5.2.8,而系统 #2 使用 PHP 5.2.9 并且有更高的 CPU、内存和硬盘速度。

intval() 和 int 的结果对比

为了证明 intval()int 得到同样的值,我进行了另一个测试:

# 输入 期待结果 INTVAL($val) (INT)$val 结果
#0 42 : 42 / 42 / 42 通过
#1 -42 : -42 / -42 / -42 通过
#2 4.2 : 4 / 4 / 4 通过
#3 ‘42’ : 42 / 42 / 42 通过
#4 ‘+42’ : 42 / 42 / 42 通过
#5 ‘-42’ : -42 / -42 / -42 通过
#6 34 : 34 / 34 / 34 通过
#7 ‘042’ : 42 / 42 / 42 通过
#8 0x1A : 1410065408 / 1410065408 / 1410065408 通过
#9 ‘1e10’ : 1 / 1 / 1 通过
#10 26 : 26 / 26 / 26 通过
#11 42000000 : 42000000 / 42000000 / 42000000 通过
#12 2147483647 : 2147483647 / 2147483647 / 2147483647 通过
#13 2147483648 : -2147483648 / -2147483648 / -2147483648 通过
#14 4.2E+20 : 0 / 0 / 0 通过
#15 ‘420000000000000000000’ : 2147483647 / 2147483647 / 2147483647 通过
#16 array() : 0 / 0 / 0 通过
#17 array(‘foo’, ‘bar’) : 1 / 1 / 1 通过

settype() 和 intval() 速度对比[系统 #1]

用于对比,我还进行了 settype()intval() 速度测试。 两者的差别并不大,但我不确定这个测试是否合理,因为并不容易直接对这个函数进行测试。既然已经跑了这个测试,我认为值得把结果同前面的数据一起分享出来。

# 输入 SETTYPE($val) INTVAL($val) 比率
#0 42 : 0.533901 / 0.477519 89%
#1 -42 : 0.533729 / 0.478345 89%
#2 4.2 : 0.536932 / 0.480030 89%
#3 ‘42’ : 0.547209 / 0.503447 92%
#4 ‘+42’ : 0.553214 / 0.501764 90%
#5 ‘-42’ : 0.551974 / 0.503403 91%
#6 34 : 0.532637 / 0.478039 89%
#7 ‘042’ : 0.552709 / 0.505796 91%
#8 0x1A : 0.536864 / 0.481672 89%
#9 ‘1e10’ : 0.550352 / 0.506748 92%
#10 26 : 0.537672 / 0.478947 89%
#11 42000000 : 0.536360 / 0.478373 89%
#12 2147483647 : 0.541348 / 0.490556 90%
#13 2147483648 : 0.539018 / 0.486669 90%
#14 4.2E+20 : 0.554357 / 0.499877 90%
#15 ‘420000000000000000000’ : 0.566189 / 0.522929 92%
#16 array() : 0.549919 / 0.505488 91%
#17 array(‘foo’, ‘bar’) : 0.578893 / 0.527864 91%

更新:

我进行了一些关于 0 + $var 的测试,因为这也是一种获得数字的方式。 这种方法没那么”类型安全”,不过作为对比,我认为有必要一起列出来:

intval() 和 0 + $var 对比结果

# 输入 期待结果 INTVAL($val) 0+$VAR 结果
#0 42 : 42 / 42 / 42 通过
#1 -42 : -42 / -42 / -42 通过
#2 4.2 : 4 / 4 / 4.2 不通过
#3 ‘42’ : 42 / 42 / 42 通过
#4 ‘+42’ : 42 / 42 / 42 通过
#5 ‘-42’ : -42 / -42 / -42 通过
#6 042 : 34 / 34 / 34 通过
#7 ‘042’ : 42 / 42 / 42 通过
#8 1e10 : 1410065408 / 1410065408 / 10000000000 不通过
#9 ‘1e10’ : 1 / 1 / 10000000000 不通过
#10 0x1A : 26 / 26 / 26 通过
#11 42000000 : 42000000 / 42000000 / 42000000 通过
#12 2147483647 : 2147483647 / 2147483647 / 2147483647 通过
#13 2147483648 : -2147483648 / -2147483648 / 2147483648 不通过
#14 420000000000000000000 : 0 / 0 / 4.2E+20 不通过
#15 ‘420000000000000000000’ : 2147483647 / 2147483647 / 4.2E+20 不通过
#16 array() : 0 / 0 / 报错 跳过
#17 array(‘foo’, ‘bar’) : 1 / 1 / 报错 跳过

(int)$val和0 + $var速度测试[系统 #1]

# 输入 (INT)$val 0+$val 比率
#0 42 : 0.068794 / 0.069249 100%
#1 -42 : 0.074688 / 0.069155 92%
#2 4.2 : 0.073207 / 0.069257 94%*
#3 ‘42’ : 0.086568 / 0.076261 88%
#4 ‘+42’ : 0.087230 / 0.080867 92%
#5 ‘-42’ : 0.090189 / 0.075923 84%
#6 042 : 0.069072 / 0.069243 100%
#7 ‘042’ : 0.088535 / 0.082137 92%
#8 1e10 : 0.072930 / 0.069512 95%*
#9 ‘1e10’ : 0.086942 / 0.082032 94%
#10 0x1A : 0.068921 / 0.069365 100%
#11 42000000 : 0.069203 / 0.069415 100%
#12 2147483647 : 0.069109 / 0.069386 100%
#13 2147483648 : 0.073053 / 0.069277 94%*
#14 420000000000000000000 : 0.092318 / 0.069463 75%*
#15 ‘420000000000000000000’ : 0.105735 / 0.211617 200%*
#16 array() : 跳过    
#17 array(‘foo’, ‘bar’) : 跳过    

*: 在上一个测试中,结果未通过

测试结论

使用 (int) 类型转换,便捷而且没有负面效果。 事实上,它在速度快的同时,还和 intval() 函数有完全一样的结果。 两者甚至还会有同样的 warning 信息。

扩展阅读

深层原因

对于作者的结论,网友 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

最终结论

  1. intintval() 快3-6倍。
  2. SEND_VARDO_FCALL 操作,是导致 intintval() 快很多的原因。