PHP使用vld扩展查看opcodes
需要分析PHP代码的性能,或者说实现同样功能的代码到底哪个更好呢?或者说想知道底层的实现可以使用VLD查看opcode。
下载安装vld扩展
该扩展以收录在 PECL
下载对应的版本安装
修改 php.ini,增加 extension=php_vld.dll
php -m
简单使用vld
代码
<?php
echo 1 + 2;
执行
$ php -dvld.active=1 test.php
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: D:\dev\php\my\test.php
function name: (null)
number of ops: 2
compiled vars: none
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
40 0 E > ECHO 3
1 > RETURN 1
branch: # 0; line: 40- 40; sop: 0; eop: 1; out0: -2
path #1: 0,
3
使用vld对比代码执行过程
比如有两个写法
写法一:
<?php
$a = 'a';
$b = 'b';
$c = 'c';
echo $a . $b . $c;
其opcodes为
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: D:\dev\php\my\test.php
function name: (null)
number of ops: 7
compiled vars: !0 = $a, !1 = $b, !2 = $c
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
40 0 E > ASSIGN !0, 'a'
41 1 ASSIGN !1, 'b'
42 2 ASSIGN !2, 'c'
44 3 CONCAT ~6 !0, !1
4 CONCAT ~7 ~6, !2
5 ECHO ~7
6 > RETURN 1
branch: # 0; line: 40- 44; sop: 0; eop: 6; out0: -2
path #1: 0,
abc
写法二:
<?php
$a = 'a';
$b = 'b';
$c = 'c';
echo $a, $b, $c;
其opcodes为
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: D:\dev\php\my\test.php
function name: (null)
number of ops: 7
compiled vars: !0 = $a, !1 = $b, !2 = $c
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
40 0 E > ASSIGN !0, 'a'
41 1 ASSIGN !1, 'b'
42 2 ASSIGN !2, 'c'
44 3 ECHO !0
4 ECHO !1
5 ECHO !2
6 > RETURN 1
branch: # 0; line: 40- 44; sop: 0; eop: 6; out0: -2
path #1: 0,
abc
我们知道字符串都是不可变的,针对字符串的操作都是会重新分配新的的内存。显然方法二更合理,这里只是列举简单的例子说明vld在优化代码上的可操作性。
line
为文件行号,此处40是因为前面有注释的代码没拷贝过来。
#*
为 opcode 编号。
!0
编译的变量,也叫 CV,以!
开头表示,compiled vars: !0 = $a, !1 = $b, !2 = $c
~6
临时变量,以~
开头,比如上面的 ~6, ~7
。
可以在某个具体的点上使用vld来对比opcodes,找到可以优化的方式。
如何阅读 opcodes 可以看看 https://blog.csdn.net/raoxiaoya/article/details/98941938
vld的配置
vld.active
是否在执行PHP时激活VLD挂钩,默认为0,表示禁用。可以使用-dvld.active=1启用。vld.execute=0
只想查看opcodes,不想真的运行代码。vld.format
是否以自定义的格式显示,默认为0,表示否。可以使用vld.format=1
,表示以自己定义的格式显示。这里自定义的格式输出是以vld.col_sep
指定的参数间隔。vld.col_sep
在vld.format
参数启用时此函数才会有效,默认为 “\t”。vld.skip_prepend
是否跳过php.ini配置文件中auto_prepend_file指定的文件, 默认为0,即不跳过包含的文件,显示这些包含的文件中的代码所生成的中间代码。此参数生效有一个前提条件:vld.execute=0
。vld.verbosity
是否显示更详细的信息,默认为1,其值可以为0,1,2,3 其实比0小的也可以,只是效果和0一样,比如0.1之类,但是负数除外,负数和效果和3的效果一样 比3大的值也是可以的,只是效果和3一样,3是最新详细的。vld.save_paths
控制是否输出文件,默认为0,表示不输出文件。vld.save_dir
指定文件输出的路径,默认路径为/tmp。vld.dump_paths
控制输出的内容,现在只有0和1两种情况,默认为1,输出内容。