从接触PHP以来就一直有单引号比双引号的快的思想,今天看了一篇文章,也是关于单引号和双引号的测试,但是我认为那片文章没有测完整,所以自己重测了一遍,发现了一个比较有意思的问题:单引号与双引号快不快可能看写法,写法不同,产生的opcode也是不一样的,自然速度也不一样了。
测试环境:
CPU : AMD Athlon(tm) II Dual-Core M300 × 2 OS : ubuntu 12.04 32bit PHP : PHP Version 5.3.10-1ubuntu3.10 tool: vld
代码1:
<?php $single_str = 'Hello quotes'; $double_str = "Hello quotes"; echo $single_str; echo $double_str; $tail = 'quotes'; $single_str_tail = 'Hello '.$tail; $double_str_tail = "Hello ".$tail; echo $single_str_tail; echo $double_str_tail; $head = 'Hello'; $single_str_head = $head.' quotes'; $double_str_head = $head." quotes"; echo $single_str_head; echo $double_str_head; ?>
通过vld产生的结果如下:
line # * op fetch ext return operands ------------------------------------------------------------- 2 0 > EXT_STMT 1 ASSIGN !0, 'Hello+quotes' 3 2 EXT_STMT 3 ASSIGN !1, 'Hello+quotes' 4 4 EXT_STMT 5 ECHO !0 5 6 EXT_STMT 7 ECHO !1 7 8 EXT_STMT 9 ASSIGN !2, 'quotes' 8 10 EXT_STMT 11 CONCAT ~3 'Hello+', !2 12 ASSIGN !3, ~3 9 13 EXT_STMT 14 CONCAT ~5 'Hello+', !2 15 ASSIGN !4, ~5 10 16 EXT_STMT 17 ECHO !3 11 18 EXT_STMT 19 ECHO !4 13 20 EXT_STMT 21 ASSIGN !5, 'Hello' 14 22 EXT_STMT 23 CONCAT ~8 !5, '+quotes' 24 ASSIGN !6, ~8 15 25 EXT_STMT 26 CONCAT ~10 !5, '+quotes' 27 ASSIGN !7, ~10 16 28 EXT_STMT 29 ECHO !6 17 30 EXT_STMT 31 ECHO !7 20 32 EXT_STMT 33 > RETURN 1
可以发现产生的opcode都是一样的,也就是单引号和双引号是一样的,但是我们改一下代码,把双引号的部分换一种写法,也就是把变量放在双引号里面,代码2:
<?php $single_str = 'Hello quotes'; $double_str = "Hello quotes"; echo $single_str; echo $double_str; $tail = 'quotes'; $single_str_tail = 'Hello '.$tail; $double_str_tail = "Hello $tail"; echo $single_str_tail; echo $double_str_tail; $head = 'Hello'; $single_str_head = $head.' quotes'; $double_str_head = "$head quotes"; echo $single_str_head; echo $double_str_head; ?>
产生的opcode如下:
line # * op fetch ext return operands ------------------------------------------------------------- 2 0 > EXT_STMT 1 ASSIGN !0, 'Hello+quotes' 3 2 EXT_STMT 3 ASSIGN !1, 'Hello+quotes' 4 4 EXT_STMT 5 ECHO !0 5 6 EXT_STMT 7 ECHO !1 7 8 EXT_STMT 9 ASSIGN !2, 'quotes' 8 10 EXT_STMT 11 CONCAT ~3 'Hello+', !2 12 ASSIGN !3, ~3 9 13 EXT_STMT 14 ADD_STRING ~5 'Hello+' 15 ADD_VAR ~5 ~5, !2 16 ASSIGN !4, ~5 10 17 EXT_STMT 18 ECHO !3 11 19 EXT_STMT 20 ECHO !4 13 21 EXT_STMT 22 ASSIGN !5, 'Hello' 14 23 EXT_STMT 24 CONCAT ~8 !5, '+quotes' 25 ASSIGN !6, ~8 15 26 EXT_STMT 27 ADD_VAR ~10 !5 28 ADD_STRING ~10 ~10, '+quotes' 29 ASSIGN !7, ~10 16 30 EXT_STMT 31 ECHO !6 17 32 EXT_STMT 33 ECHO !7 20 34 EXT_STMT 35 > RETURN 1
现在就能看出区别了,对比11,12以及14,15,16,或者24,25以及27,28,29,就可以发现使用单引号产生了CONCAT和ASSIGN两个动作,使用双引号产生了ADD_STRING,ADD_VAR,ASSIGN三个动作,貌似是单引号要快,因为少一个动作,但是我们还没测CONCAT 是否真的比ADD_STRING,ADD_VAR快,这个可以采用基准测试,或者直接查看对应的C函数代码比较得知。
总结: 采用代码1中的写法,单引号和双引号的作用是一样的,速度自然也是一样的,采用代码2中的写法,单引号和双引号产生的opcode不一样,虽然多双引号的opcode多一个动作,但是单从opcode还是无法判断单引号要比双引号要快,如果是这样的话后面还是需要其他的测试。
还有一种造成速度差异的是在分析语法和解释阶段,我看过的那片文章提到了这样一句话:"至于编译阶段,双引号和单引号的区别也是很大的, 我就举个数字来说明: 在scanning阶段, 对于双引号的词法规则有14条,而对于单引号,仅仅只有6条。"
如果是这样的话,说明双引号在解释编译阶段要慢,那是不是可以通过opcode缓存来消除差异?