OpCode,即Operation Code,操作码。通常是指计算机指令中的一部分,用于指定要执行的操作, 指令的格式和规范由处理器的指令规范指定。

通常opcode还有另一种称谓:字节码(byte codes)。例如Java编译后生成的class文件。

PHP中的opcode则属于后者,PHP构建在Zend虚拟机(Zend VM)之上。PHP的opcode就是Zend虚拟机中的指令。当Zend 引擎完成对脚本代码的编译后,便将它们生成可以直接运行的中间代码,即OpCode。

比如写了如下PHP代码:

echo "Hello World!";

$a = 1 +1;

echo $a;

?>

PHP执行这段代码会经过如下4个步骤(确切的来说,应该是PHP的语言引擎Zend):

1. Scanning(Lexing) ,Zend Engine(Zend引擎),调用词法分析器(Lex生成的,源文件在Zend/zend_language_sanner.l),将我们要执行的PHP源文件,去掉空格 ,注释,分割成一个一个的语言片段(Tokens)。

2. Parsing, Zend引擎会将得到的token forward给语法分析器(yacc生成, 源文件在 Zend/zend_language_parser.y),将Tokens转换成简单而有意义的表达式。

3. Compilation, 将表达式编译成Opocdes,opcode一般会以op array的形式存在。

4. Execution, Zend引擎调用zend_executor来顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。

每一次请求到来的时候,都是这样一个过程,但是很明显每次都需要编译,是非常低效的。因为PHP源码不变,OpCode就不会改变,所以前面的步骤就不需要每次都进行,这就是所谓的OpCode缓存,就是将第三步生成的OpCode缓存下来,这样下一次请求来的时候就不需要前三步,直接执行OpCode就可以了,从而可以大大的提升执行速度。

关于Opcode缓存

详细的opcode编译过程可以看鸟哥的博客《深入理解PHP原理之OpCode》。

那如何可以看到我们的PHP脚本,最终被编译成什么样的呢? 也就是说,OpCode长的什么样子呢? 在PECL中已经有这样的模块,可以让我们直接使用了,那就是由 Derick Rethans开发的VLD (Vulcan Logic Dissassembler)模块。只需要下载这个模块,并把他作为PHP扩展载入,就可以通过简单的设置,来得到脚本编译的结果了。

1. 安装VLD

下载地址:http://pecl.php.net/package/vld

windows直接下载dll拷贝到php的ext目录中,然后在php.ini中加上extension=php_vld.dll就可以了。

Linux下载编译安装,然后同样php.ini加上extension=vld.so即可。

2. 使用VLD

php -dvld.active=1 test.php

比如上面的代码,就可以得到:

PHP构建在Zend 引擎之上。PHP的opcode就是Zend虚拟机中的指令,在PHP源码({PHPSRC}/Zend/zend_vm_opcodes.c)中可以发现,一共有187条指令。顺便说一下,目前PHP源码托管到github上了,源码地址:https://github.com/php/php-src/

在PHP7之前的源码中,opcode({PHPSRC}/Zend/zend_compile.h)是这样的:

struct _zend_op {

opcode_handler_t handler; // 执行该opcode时调用的处理函数

znode result;

znode op1;

znode op2;

ulong extended_value;

uint lineno;

zend_uchar opcode;  // opcode代码

};

最新的PHP7中的是这样,可以看到增加了三个字段,表示操作数的数据类型,这大概是为PHP7可以支持强类型修改的吧(猜的)。

struct _zend_op {

const void *handler;

znode_op op1;

znode_op op2;

znode_op result;

uint32_t extended_value;

uint32_t lineno;

zend_uchar opcode;

zend_uchar op1_type;

zend_uchar op2_type;

zend_uchar result_type;

};

各个字段的含义:

(1)handler:op的执行句柄。

(2)op1, op2, result:这三个字段是op的操作数和操作结果载体,当然并不是每个op都需要使用这三个字段,根据op的功能不同,会使用其中某些字段。比如类型为ZEND_ECHO的op只需要使用op1,功能就是将op1中的相应的值输出。

void zend_do_echo(const znode *arg TSRMLS_DC) {

zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);

opline->opcode = ZEND_ECHO;

opline->op1 = *arg;

SET_UNUSED(opline->op2);

}

PHP7之前的代码是znode类型,而php7中是znode_op类型。

PHP7中znode_op和znode的定义:

typedef union _znode_op {

uint32_t constant;

uint32_t var;

uint32_t num;

uint32_t opline_num; /* Needs to be signed */

#if ZEND_USE_ABS_JMP_ADDR

zend_op *jmp_addr;

#else

uint32_t jmp_offset;

#endif

#if ZEND_USE_ABS_CONST_ADDR

zval *zv;

#endif

} znode_op;

typedef struct _znode { /* used only during compilation */

zend_uchar op_type;

zend_uchar flag;

union {

znode_op op;

zval constant; /* replaced by literal/zv */

} u;

} znode;

PHP7之前版本znode:

typedef struct _znode {

int op_type;

union {

zval constant;

zend_uint var;

zend_uint opline_num; /*  Needs to be signed */

zend_op_array *op_array;

zend_op *jmp_addr;

struct {

zend_uint var;  /* dummy */

zend_uint type;

} EA;

} u;

} znode;

具体变化的原因由于并没有仔细的看源码,所以还不太明白,有空研究一下源码。

其中op_type这个int类型的字段定义操作数的类型,这些类型一共有五种:

#define IS_CONST    (1<<0)

#define IS_TMP_VAR  (1<<1)

#define IS_VAR      (1<<2)

#define IS_UNUSED   (1<<3)    /* Unused variable */

#define IS_CV       (1<<4)    /* Compiled variable */

IS_CONST:

表示常量,例如$a = 123; $b = “hello”;这些代码生成OP后,123和”hello”都是以常量类型操作数存在。

IS_TMP_VAR:表示临时变量,临时变量一般在前面加~来表示,这是一些OP执行过程中需要用到的中间变量,例如初始化一个数组的时候,就需要一个临时变量来暂时存储数组zval,然后将数组赋值给变量。

IS_VAR:一般意义上的变量,以$开发表示,此种变量本人目前研究的较少,暂不介绍

IS_UNUSED :暂时不介绍,从名字来看应该是标识为不使用

IS_CV:这种类型的操作数比较重要,此类型是在PHP后来的版本中(大概5.1)中才出现,CV的意思是compiled variable,即编译后的变量,变量都是保存在一个符号表中,这个符号表是一个哈希表,试想如果每次读写变量的时候都需要到哈希表中去检索,势必会对效率有一定的影响,因此在执行上下文环境中,会将一些编译期间生成的变量缓存起来,此过程以后再详细介绍。此类型操作数一般以!开头表示,比如变量$a=123;$b=”hello”这段代码,$a和$b对应的操作数可能就是!0和!1, 0和1相当于一个索引号,通过索引号从缓存中取得相应的值。

(3)opcode:与CPU的指令类似,有一个标示指令的opcode字段。此字段保存的整形值即为op的编号,用来区分不同的op类型,opcode的可取值都被定义成了宏,可以在{PHPSRC}/Zend/zend_vm_opcodes.h中看到这些宏的定义,类似如({PHPSRC}/Zend/zend_vm_opcodes.h):

#define ZEND_NOP 0

#define ZEND_ADD 1

#define ZEND_SUB 2

#define ZEND_MUL 3

#define ZEND_DIV 4

#define ZEND_MOD 5

#define ZEND_SL 6

#define ZEND_SR 7

#define ZEND_CONCAT 8

(4)lineno:对应PHP源码中的行号。

(5)extended_value:PHP不像汇编那么底层,在脚本实际执行的时候可能还需要其他更多的信息,保存在extended_value字段。

转载请注明出处fullstackdevel.com:SEAN是一只程序猿 » PHP之opcode及VLD使用

php windows vld,PHP之opcode及VLD使用相关推荐

  1. php opcodevld,利用PHP扩张vld查看PHP opcode

    作者:zhanhailiang 日期:2013-03-04 首先下载最新版vld扩展:~/public_html/php-5.3.13/ext> wget http://pecl.php.net ...

  2. VLD的安装使用及其问题

    目录 下载 VLD 安装 VLD 使用 VLD 打开项目 配置 VLD 环境(VS 版本在 2015 及其以下的无需配置) 使用 VLD 问题 应用程序无法正常启动 0xc150002 无法显示内存泄 ...

  3. Visual Leak Detector (VLD)使用

    Visual C++内置内存泄露检测工具,但是功能十分有限.VLD就相当强大,可以定位文件.行号,可以非常准确地找到内存泄漏的位置,而且还免费.开源! 在使用的时候只要将VLD的头文件和lib文件放在 ...

  4. vs 2010 下使用VLD工具

    名词解释: 1.stack trace:调用堆栈信息 2.debug heap:调试堆 3.Allocation Hook:向调试堆注册的回调函数,当申请内存时,调试堆即调用此回调函数 前言 VC++ ...

  5. QT使用VLD检测内存泄漏

    QT使用VLD检测内存泄漏 下载VLD VLD版本:vld-2.5.1-setup 下载地址:https://kinddragon.github.io/vld/ 安装VLD 直接双击安装,选择安装位置 ...

  6. qt5使用内存检测工具vld查看内存泄漏

    什么是vld? Visual Leak Detector是一款用于Visual C++的免费的内存泄露检测工具.相比较其它的内存泄露检测工具,它在检测到内存泄漏的同时,还具有如下特点: 1. 可以得到 ...

  7. Qt Creator 中使用VLD检测内存泄漏

    简介 Visual Leak Detector是一款用于Visual C++的免费的内存泄露检测工具.相比较其它的内存泄露检测工具,它在检测到内存泄漏的同时,还具有如下特点:可以得到内存泄漏点的调用堆 ...

  8. 内存泄漏查找工具VLD的使用

    1.什么是vld? Visual Leak Detector(VLD)同样是一款开源检测内存泄露软件的简称. 官方的介绍如下地址:在Visual Studio调试器下运行程序时,Visual Leak ...

  9. 在vs中使用 vld 进行内存泄漏检测

    下载 vld https://github.com/KindDragon/vld 安装 vld 后记录安装目录 C:\Program Files (x86)\Visual Leak Detector ...

  10. 内存泄露检测工具VLD相关配置

    参考链接: VLD(Visual LeakDetector)内存泄露库的使用 VS2019编译 内存泄漏检测工具VLD 一.源码下载 源码下载链接:https://github.com/KindDra ...

最新文章

  1. jvm 堆外内存_NIO效率高的原理之零拷贝与直接内存映射
  2. 邮件发送类,支持HTML格式,支持优先级设置
  3. CentOs 6.0 下安装cacti的syslog插件
  4. Duo js 一个非常酷的前端打包工具
  5. 再有人问 Java 中的注解就把这篇文章丢给他!
  6. ML之DT(树模型):DT(树模型算法)算法的简介、代码定义、案例应用之详细攻略
  7. 微服务框架 Go-Micro 集成 Nacos 实战之服务注册与发现
  8. uni-app内置地图轨迹_MIUI11 新增亲情守护,支持安全围栏、运动轨迹功能
  9. Linux kernel同步机制
  10. docker 安装部署 Jenkins 2.322
  11. qt如何安装python_安装Python QT,PythonQT,的
  12. 人工智能是一个工程问题,而不是魔术!
  13. 不加载任何包,手撕一个R语言版BP神经网络模型
  14. Centos7 Kubernetes(k8s) 开发服务器(单服务器)部署 grafana 度量分析和可视化
  15. 数值分析思考题(钟尔杰版)参考解答——第一章
  16. python爬虫之JS混淆加密、字体反爬
  17. memory repair
  18. 新型单词记忆法汇总(沪江英语):
  19. 解决springboot无法访问此网站,springboot启动后无法访问网站
  20. RSA算法计算d的两种方法。

热门文章

  1. MFC通过CImage绘制透明图层的png图片
  2. 现代通信技术之分组交换技术
  3. Python之计算机算法基础总结(借鉴、整理)、排序算法、查找算法
  4. iso22000食品安全管理体系_ISO22000-食品安全管理体系认证
  5. Android速度仪表盘,速度评级小车动画(模仿电脑版360宽带测速器)
  6. 计算机设备管理器驱动,设备管理器安装驱动程序的详细教程
  7. Android-APP之桌面宠物
  8. 怎样改变计算机桌面的特效主题,教你如何更改电脑主题,桌面,图标,系统主题 - 飞机城社区论坛 - 阎良论坛 飞机城论坛,......
  9. ManualResetEvent使用说明
  10. 使用fdisk给新增加硬盘分区