编译php文件的方法

  介绍

这篇文章将为大家详细讲解有关编译php文件的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

php是解析型高级语言,事实上从Zend内核的角度来就看php是一个普通的C程序,它主要有函数,我们写的php代码是这个程序的输入,然后经过内核的处理输出结果,内核将php代码“翻译“为C程序可识别的过程就是php的编译。

推荐课程:php教程。

编译php文件的方法

C程序在编译时将一行行代码编译为机器码,每一个操作都认为是一条机器指令,这些指令写入到编译后的二进制程序中,执行的时候将二进制程序加载进相应的内存区域(常量区,数据区,代码区),分配运行栈,然后从代码区起始位置开始执行,这是C程序编译,执行的简单过程。

同样,php的编译与普通的C程序类似,只是php代码没有编译成机器码,而是解析成了若干条操作码数组,每条操作码就是C里面普通的结构、含义对C应程序的机器指令,执行的过程就是引擎依次执行操作码,比如我们在php里定义一个变量:<代码>=123美元;>

在zend_compile。h文件中,操作码结构:

struct _zend_op {   const void *处理程序;//对应执行C的语言函数,即每条操作码都有一个C函数处理   znode_op op1;//操作数1   znode_op op2;//操作数2   znode_op结果;//返回值   uint32_t extended_value;   uint32_t lineno;   zend_uchar操作码;//操作码指令   zend_uchar op1_type;//操作数1类型   zend_uchar op2_type;//操作数2类型   zend_uchar result_type;//返回值类型   };


所以PHP的解析过程任务就是将PHP代码(通过词法分析re2c,语法分析野牛)转化为操作码数组,代码里的所有信息都保存在操作码中,然后将操作码数组交给zend引擎执行,操作码就是内核具体执行的命令,比如赋值,加减操作,函数调用等,每一条操作码都对应一个处理,这些处理程序是提前定义好的C函数。

struct _zend_op_array {//普通是普通函数或类成员方法对应的操作码快速访问时使用的字段   *//*常见的元素   zend_uchar类型;   zend_uchar arg_flags [3];/* bitset arg_info。pass_by_reference */uint32_t fn_flags;   zend_string * function_name;   zend_class_entry *范围;   zend_function *原型;   uint32_t num_args;   uint32_t required_num_args;   zend_arg_info * arg_info;   *//*的共同元素      uint32_t * refcount;      uint32_t去年;//操作码指令数组   zend_op *操作码;//PHP代码里定义的变量数:op_type为IS_CV的变量,不含IS_TMP_VAR, IS_VAR的//编译前此值为0,然后发现一个新变量这个值就加1   int last_var;//临时变量数:op_type为IS_TMP_VAR, IS_VAR的变量   uint32_t T;//PHP变量名数组   zend_string * * var;//这个数组在ast编译期间配合last_var用来确定各个变量的编号,非常重要的一步操作      int last_live_range;   int last_try_catch;   zend_live_range * live_range;   zend_try_catch_element * try_catch_array;//静态变量符号表:通过静态声明的/* */静态变量支持   散列表* static_variables;      zend_string *文件名;   uint32_t line_start;   uint32_t line_end;   zend_string * doc_comment;   uint32_t early_binding;/*声明*/延迟的链表//字面量数量   int last_literal;//字面量(常量)数组,这些都是在PHP代码定义的一些值   zval *文字;//运行时缓存数组大小   int cache_size;//运行时缓存,主要用于缓存一些znode_op以便于快速获取数据,后面单独介绍这个机制   void * * run_time_cache;      void *保留[ZEND_MAX_RESERVED_RESOURCES];   };

操作码指令:即PHP代码具体对应的处理动作,与二进制程序中的代码段对应
字面量存储:PHP代码中定义的一些变量初始值,调用的函数名称,类名称,常量名称等等称之为字面量,这些值用于执行时初始化变量,函数调用等等
变量分配情况:与字面量类似,这里指的是当前操作码定义了多少变量,临时变量,每个变量都有一个对应的编号,执行初始化按照总的数目一次性分配zval,使用时也完全按照编号索引,而不是根据变量名索引

从PHP代码到操作码是怎么实现的?

最容易想到的方式就是正则匹配,当然过程没有这么简单。PHP编译过程包括词法分析,语法分析,使用re2c,野牛完成,旧的PHP版本直接生成了操作码,PHP7新增了抽象语法树(AST),在语法分析阶段生成AST,然后再生成操作码数组

编译php文件的方法