• 技术文章 >后端开发 >php教程

    如何编译php文件

    (*-*)浩(*-*)浩2020-09-14 16:29:59原创5862
    PHP是解析型高级语言,事实上从Zend内核的角度来看PHP就是一个普通的C程序,它有main函数,我们写的PHP代码是这个程序的输入,然后经过内核的处理输出结果,内核将PHP代码"翻译"为C程序可识别的过程就是PHP的编译。

    推荐课程:PHP教程

    php入门到就业线上直播课:进入学习

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

    同样,PHP的编译与普通的C程序类似,只是PHP代码没有编译成机器码,而是解析成了若干条opcode数组,每条opcode就是C里面普通的struct,含义对应C程序的机器指令,执行的过程就是引擎依次执行opcode,比如我们在PHP里定义一个变量:$a = 123;,最终到内核里执行就是malloc一块内存,然后把值写进去。

    在zend_compile.h文件中,opcode结构:

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

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

    struct _zend_op_array {
        //common是普通函数或类成员方法对应的opcodes快速访问时使用的字段
        /* Common elements */
        zend_uchar type;
        zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
        uint32_t fn_flags;
        zend_string *function_name;
        zend_class_entry *scope;
        zend_function *prototype;
        uint32_t num_args;
        uint32_t required_num_args;
        zend_arg_info *arg_info;
        /* END of common elements */
    
        uint32_t *refcount;
    
        uint32_t last;
         //opcode指令数组
        zend_op *opcodes;
    
        //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 **vars;//这个数组在ast编译期间配合last_var用来确定各个变量的编号,非常重要的一步操作
    
        int last_live_range;
        int last_try_catch;
        zend_live_range *live_range;
        zend_try_catch_element *try_catch_array;
    
        //静态变量符号表:通过static声明的
        /* static variables support */
        HashTable *static_variables;
    
        zend_string *filename;
        uint32_t line_start;
        uint32_t line_end;
        zend_string *doc_comment;
        uint32_t early_binding; /* the linked list of delayed declarations */
    
        //字面量数量
        int last_literal;
        //字面量(常量)数组,这些都是在PHP代码定义的一些值
        zval *literals;
    
        //运行时缓存数组大小
        int  cache_size;
        //运行时缓存,主要用于缓存一些znode_op以便于快速获取数据,后面单独介绍这个机制
        void **run_time_cache;
    
        void *reserved[ZEND_MAX_RESERVED_RESOURCES];
    };

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

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

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

    以上就是如何编译php文件的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    专题推荐:php
    上一篇:做网站会用到什么语言? 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• wamp怎么升级php版本• ThinkPHP5是什么时候发布的• 初次装php对电脑有什么要求?• php需要学哪些?
    1/1

    PHP中文网