写在前面的话,在PHP的生命周期中
1.词法分析(zend_language_scanner)
Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens);
2.语法分析(zend_language_parser)
Parsing, 将Tokens转换成简单而有意义的表达式
3.编译(compiler)
Compilation, 将表达式编译成Opocdes
4.Zend Engine(zend_vm_execute)
Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。
token_get_all(),这个函数就可以将一段PHP代码 Scanning成Tokens;
➜ wdy cat for.php
<?php
$tokens = token_get_all('<?php echo 123;?>');
print_r($tokens);
?>
➜ wdy php for.php
Array
(
[0] => Array
(
[0] => 374
[1] => <?php
[2] => 1
)
[1] => Array
(
[0] => 317
[1] => echo
[2] => 1
)
[2] => Array
vld介绍
vld是PECL(PHP 扩展和应用仓库)的一个PHP扩展,现在最新版本是 0.14.0(2016-12-18),它的作用是:显示转储PHP脚本(opcode)的内部表示(来自PECL的vld简介)。简单来说,可以查看PHP程序的opcode。
安装vld扩展
- 下载官方插件压缩包
http://pecl.php.net/package/vld - 安装
# wget http://pecl.php.net/get/vld-0.14.0.tgz
# tar zxvf vld-0.14.0.tgz
root@wdy vld-0.14.0 # phpize
Configuring for:
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
# ./configure --with-php-config=/usr/local/php/bin/php-config
# make && make install
Build complete.
Don’t forget to run ‘make test’.Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/
# vi /usr/local/php/etc/php.ini
extension = “vld.so”
至此,VLD就安装完了。写个简单的测试文件
root@wdy ~ # cat yield.php
<?php
function xrange($start,$end,$step = 1){
for($i = $start; $i<=$end;$i += $step){
yield $i;
}
}
#foreach(xrange(1,1000000) as $num){
# echo $num,"\n";
#}
$range = xrange(1,1000000);
var_dump($range);
var_dump($range instanceof Iterator);
?>
root@wdy ~ # php -dvld.active=1 yield.php
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 62) Position 1 = -2
filename: /root/yield.php
function name: (null) /*opcode所属函数。全局,此处为null。每个函数会有对应的完整的opcode信息。*/
number of ops: 12 /*此段opcode有多少个运算操作*/
compiled vars: !0 = $range
/*op list 核心部分 需要对照zend文档查看*/
/*line 操作所在的行号*/
/*#* 操作*/
/*op 操作符 对应c的操作*/
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
3 0 E > NOP
14 1 SEND_VAL 1
2 SEND_VAL 1000000
3 DO_FCALL 2 $0 'xrange'
4 ASSIGN !0, $0
15 5 SEND_VAR !0
6 DO_FCALL 1 'var_dump'
16 7 FETCH_CLASS 128 :3 'Iterator'
8 INSTANCEOF ~4 !0, $3
9 SEND_VAL ~4
10 DO_FCALL 1 'var_dump'
18 11 > RETURN 1
branch: # 0; line: 3- 18; sop: 0; eop: 11; out1: -2
path #1: 0,
Function xrange:
Finding entry points
Branch analysis from position: 0
Jump found. (Code = 45) Position 1 = 10, Position 2 = 8
Branch analysis from position: 10
Jump found. (Code = 161) Position 1 = -2
Branch analysis from position: 8
Jump found. (Code = 42) Position 1 = 6
Branch analysis from position: 6
Jump found. (Code = 42) Position 1 = 4
Branch analysis from position: 4
filename: /root/yield.php
function name: xrange
number of ops: 11
compiled vars: !0 = $start, !1 = $end, !2 = $step, !3 = $i
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
3 0 E > RECV !0
1 RECV !1
2 RECV_INIT !2 1
4 3 ASSIGN !3, !0
4 > IS_SMALLER_OR_EQUAL ~1 !3, !1
5 > JMPZNZ 8 ~1, ->10
6 > ASSIGN_ADD 0 !3, !2
7 > JMP ->4
5 8 > YIELD !3
6 9 > JMP ->6
7 10 > > GENERATOR_RETURN
branch: # 0; line: 3- 4; sop: 0; eop: 3; out1: 4
branch: # 4; line: 4- 4; sop: 4; eop: 5; out1: 10; out2: 8
branch: # 6; line: 4- 4; sop: 6; eop: 7; out1: 4
branch: # 8; line: 5- 6; sop: 8; eop: 9; out1: 6
branch: # 10; line: 7- 7; sop: 10; eop: 10; out1: -2
path #1: 0, 4, 10,
path #2: 0, 4, 8, 6, 4, 10,
End of function xrange
object(Generator)#1 (0) {
}
bool(true)