初识opcode

写在前面的话,在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扩展

  1. 下载官方插件压缩包
    http://pecl.php.net/package/vld
  2. 安装

# 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”

php-config

至此,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)
参考资料
### 什么是Opcode在编程中的含义和用法 在编程中,**opcode**(操作码)是机器语言指令的一部分,用于指定计算机应执行的具体操作。它通常是一个简短的代码或数字,代表特定的操作类型,例如加法、减法、加载数据、存储数据等。Opcode 是汇编语言和低级编程的核心概念之一。 在汇编语言中,每条指令由 opcode 和操作数(operands)组成。Opcode 决定了指令的行为,而操作数则指定了指令作用的对象。例如,在 x86 汇编中,`MOV` 是一个常见的 opcode,表示将数据从一个位置复制到另一个位置[^1]。 #### Opcode 的典型用法 1. **汇编语言中的使用** 在汇编语言中,程序员通过编写人类可读的指令(如 `ADD`, `SUB`, `MOV` 等)来定义程序逻辑。这些指令会被汇编器转换为二进制形式,其中每个指令的第一个部分就是 opcode。例如: ```asm MOV AX, BX ``` 这里的 `MOV` 是 opcode,表示将寄存器 BX 的值移动到寄存器 AX 中。 2. **虚拟机中的使用** 在现代编程语言中,虚拟机(如 Java 虚拟机或 Python 字节码解释器)也使用 opcode 来表示高级语言代码的中间表示形式。例如,Python 的字节码可能包含类似以下的指令: ```python LOAD_CONST # 加载常量 STORE_NAME # 存储变量名 BINARY_ADD # 执行加法 RETURN_VALUE # 返回结果 ``` 每个指令都有对应的 opcode,解释器会根据 opcode 执行相应的操作。 3. **硬件级别的使用** 在硬件层面,CPU 直接执行二进制形式的 opcode。例如,x86 架构中的 `0x90` 是 `NOP`(无操作)指令的 opcode,表示 CPU 不执行任何操作并继续下一条指令。 #### 示例代码 以下是一个简单的 x86 汇编代码示例,展示如何使用 opcode: ```asm section .data num1 db 5 num2 db 3 section .text global _start _start: mov al, [num1] ; 将 num1 的值加载到 AL 寄存器中 add al, [num2] ; 将 num2 的值加到 AL 中 mov [num1], al ; 将结果存储回 num1 ``` 在这个例子中,`mov` 和 `add` 是 opcode,分别表示加载数据和执行加法操作。 #### 特性与设计原则 - Opcode 应该易于识别且不易与其他有效值混淆[^2]。 - 在调试过程中,无效的 opcode 应该能够触发异常或中断,以便开发者快速定位问题[^4]。 ### 结论 Opcode 是编程中不可或缺的基本单元,尤其在低级编程和硬件交互中具有重要作用。无论是汇编语言还是现代虚拟机,opcode 都是实现程序功能的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值