php运行汇编,php脚本的执行过程(编译与执行相分离)
php的编译和执行是分离开的,亦即:先执行完编译,而后再执行。很多人会说:c++也是如此啊,确实。不过php的这种分离可以给我们提供很多便利,当然不可避免也有很有缺点。
先说一下整个过程:
①php会调用编译函数zend_compile_file()来进行编译。 这个函数的具体实现其实是包括两个主要过程的:词法分析(Lex实现),语法分析(Yacc实现)。当执行完这个函数之后:php脚本的编译就算结束了。 这个函数的输入是:php脚本文件,而输出则是op_array.简单一点说:编译过程就是把脚本给解析成一条条php虚拟机可以处理的指令,而op_array就是这些指令做成的一个array而已(这很类似一些编译型语言编译产生的汇编代码了,也是一条条的命令)。
②:之后php虚拟机会调用zend_execute()这个函数来执行。该函数的输入就是上边编译阶段产生的op_array,在这里他会解析每条命令并进行处理。 由于op命令一共有150左右,所以它需要处理这150中命令。这里会产生一个很有意思的问题:它是如何处理这150种命令的呢?首先每条命令都是有对应的处理器来进行处理的。所以:虚拟机会依据op_array中各条命令的类型来分发给响应的处理器来进行处理。
这里有两个小问题: 1:这里的处理器是什么? 2:如何分发的?
要解答这两个问题都是要从分发机制上来解释:php虚拟机分发命令的机制有三种:CALL, SWITCH, 和GOTO这三种类型.php默认是使用CALL方式, 也就是所有的opcode处理器都定义为函数, 然后供虚拟机调用. 这种方式是传统的方式, 也一般被认为是最稳定的方式.而SWITCH方式和GOTO方式则是通过switch和goto来分发opcode到对应的处理逻辑(段)执行的.
那现在来回答上边两个问题:
1:处理器其实是处理op命令的逻辑。其可以以函数的形式存在,也可能是以逻辑段的方式存在,这取决于命令的分发方式。
2:分发方式有call,switch和goto三种。哪种效率高呢?其实从上边解释已经可以初步了解了。switch和goto都是在zend_execute()这个函数中有对应的逻辑段,直接执行就可以了。而call是在zend_execute()这个函数中执行函数调用。明摆着:函数调用效率是最低的,调用一次就得压栈啊!所以效率上:call是最低的。对于switch和goto:比如要执行第三种命令的处理:switch还要先挨个判断是不是前两种,而goto根本不需要判断,直接跳到第三种命令的逻辑代码段去执行,这比switch少了顺序从上到下判断的损耗,所以:goto效率又比switch要高。 所以这三种分发方式总体而言:goto > switch > call
题外话:由于php默认是call,如果你想进一步榨干php的效能,可以更改下其命令分发方式为goto。不过用goto方式虽然提高了执行速度,但是编译速度上其实最慢的喔。
--------------------------------------------------------------------------------------------------------------------------------------------------
再说一下php这种编译和执行分离的弱点:
其实也不能算是弱点,虽然zend engine(php的虚拟机)将编译和执行严格分开,但是对于用户而言:就跟没分开一样,因为我每次执行一个php脚本请求都是要执行:编译->执行 这两个阶段。任何一个阶段都少不了。那么这一点我们可以拿来和c++这种编译型语言做一下对比: 同一个请求运行100遍
①对于c++,由于其前期只要编译一遍,编译好就不会再重复编译了,只需要执行就ok,所以其损耗为:
1次编译 + 100次执行
②对于php,其每次都要编译+执行,所以其损耗为:
100次编译 + 100次执行
显然:解释性语言从数量上来看:其消耗是比编译型语言多的多。说白了就是:php这种编译和执行相分离并不是真正的分离。而c++那种才算是真正的分离。
php也早就意识到这个问题了,于是就想了一个办法来解决这个问题:这个解决方案就是eAccelerator。主要思路如下:
当脚本第一次运行后,以某种方式保存编译后脚本(里边存放的是op_array),在我们规定的缓存有效时间内,当第二次运行该脚本时就不在进行重复性的编译工作,而是直接调用执行前面保存的编译后文件,大大提高了程序性能。
这种方式一定程度上提高了php的效率,但不是最终极的方法,最终极的还是改成编译型语言那种方式好了,吼吼~~~
---------------------------------------------------------------------------------------------------------------------------------------------------
最后说一下php编译和执行分离的优点;
这个优点其实是针对程序员而言,对用户而言没什么。因为这两个阶段的分离,我们可以在这里做一些我们想做的事情。
比如想做文件加解密,你想把一些php脚本源码文件加密,让用户看不到源码。同时呢这个加密后的源码文件又可以被php虚拟机所解析和处理。当然:要实现这个前提是你先想好加解密算法并保证这个是可逆的过程。
现在你对php源码文件已经加密了,此时你需要定义一下这种加密文件的后缀,假设为:*.buaa。 那问题就是:我们怎么让php虚拟机可以处理这种后缀的文件呢?这就要用到上边所说的编译和执行相分离的过程了。
回想一下:编译阶段的输入是php源文件,输出是op_array。 ok,我们就在这个阶段做文章。主要思路为:首先在zend_compile_file()这个编译函数中:看一下输入文件的后缀:如果是正常的.php那就走正常逻辑,如果是*.buaa,那就先解密然后再走正常逻辑。。。
哈~就是这么简单。当然:这个过程没有所说的这么简单,而且你也不可能直接修改zend_compile_file()函数,最后是自己扩展实现一个模块来处理这个过程。
本文参考了如下博文:
1:http://www.laruence.com/2008/08/14/250.html
2:http://yanbin.org/archive/zend-engines-fantasy.html
3:http://www.laruence.com/2008/06/18/221.html
4:http://www.laruence.com/2009/10/15/1131.html
php运行汇编,php脚本的执行过程(编译与执行相分离)相关推荐
- 简述计算机程序执行过程,计算机程序的执行过程
[size=small]微型计算机中程序的执行过程 计算机采取"存储程序与程序控制"的工作方式,即事先把程序加载到计算机的存储器中,当启动运行后,计算机便会自动按照程序的要示进行工 ...
- python执行shell命令、并获取执行过程信息_python执行使用shell命令方法
1. os.system(shell_command) 直接在终端输出执行结果,返回执行状态0,1 此函数会启动子进程,在子进程中执行command,并返回command命令执行完毕后的退出状态,如果 ...
- JavaScript的执行过程(深入执行上下文、GO、AO、VO和VE等概念)
目录 JavaScript的执行过程 前言 1.初始化全局对象 2.执行上下文栈(调用栈) 3.调用栈调用GEC的过程 4.函数执行上下文 5.变量环境和记录 6.全局代码执行过程(函数嵌套) 总结: ...
- 一个php请求的执行过程,PHP程序执行的过程原理
为了以后能开发PHP扩展,就一定要了解PHP的执行顺序.这篇文章就是为C开发PHP扩展做铺垫. Web环境我们假设为Apache.在编译PHP的时候,为了能够让Apache支持PHP,我们会生成一个m ...
- JAVA执行过程sql,SQL 执行过程
一.MySQL架构总览: 二.查询执行流程 一条select的生存周期: 流程: 1.连接 1.1客户端发起一条Query请求,监听客户端的'连接管理模块'接收请求: 1.2将请求转发到'连接进/线程 ...
- JSP起源、JSP的运行原理、JSP的执行过程
JSP起源 在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变. 如果使用Servlet程序来输出只有局部内容需要动态改变的网页,其中所有的静态内容也需要程序员用Java程序 ...
- linux脚本执行过程中被挂起,Linux学习笔记(八)——脚本执行的过程控制
一.脚本执行过程中的控制 之前的内容中,运行编写好的脚本时都是在命令行上直接确定运行的,并且运行的脚本是实时的,这并不是脚本唯一的运行方式,下面的内容是脚本的其他运行方式.例如在Linux系统中如何控 ...
- JSP的执行过程(详解)
要了解JSP的执行过程,首要要搞懂什么是JSP,JSP的全称是Java Server Pages,里面包含html标签.css样式.JavaScript脚本和Java代码. 下面我们来说说JSP的执行 ...
- javascript 编译与执行过程
Javascript预编译和执行过程 1. 在执行前会进行类似"预编译"的操作:首先会创建一个当前执行环境下的活动对象,并将那些用 var申明的变量设置为活动对象的属性,但是此时这 ...
最新文章
- c语言字母g,C语言库函数(G类字母) - 1.doc
- windoes server 关闭服务端口方法、漏洞补丁解决
- VTK:相互作用之SelectAVertex
- 进程组 会话 作业
- spark 笔记 1: 如何着手
- AutoML数据增广
- eBPF bpftrace 实现个UNIX socket抓包试试
- 自己调用NTDLL函数
- 手把手教,使用VMware虚拟机安装Windows XP系统,爷青回
- oracle 11g 映像文件有效 但不适用于此计算机类型,《计算机应用基础》期末考试模拟练习题(含答案)...
- 眨眼视频制作与生成活体视频生成
- Justinmind Prototyper中如何使用变量达到一些效果
- 武林外传之同福奇缘 【安卓游戏】
- Consumer消息拉取和消费流程分析
- mysql 危险字符_PHP过滤指定字符串,过滤危险字符
- ckc交易什么意思_股前加r是什么意思?股市kdj线图如何看?
- php mysql好学吗_PHP+MySQL好不好学?
- 一边“打工”一边“合作”,微盟为何联手腾讯推出私域加速计划?
- scrapy框架之分布式爬虫
- 傲腾内存不支持linux吗,英特尔一面优化傲腾可持续内存性能 一面不忘科普
热门文章
- python调用计算器卡死_Python+tkinter使用40行代码实现计算器功能
- python的两种循环结构_python分支和循环结构
- 来,拆一堆芯片看看!
- 知乎高赞、高逼格 1024 程序员节礼物
- 基于 xilinx vivado 的PCIE ip核设置与例程代码详解
- java kotlin lateinit_kotlin - 如何检查“lateinit”变量是否已初始化?
- mysql 按顺序添加_MySQL按顺序排序
- oracle外部表kup-04040,【故障处理】19c PDB中创建外部表时,出现KUP-04040报错
- k8s部署jar包_使用Kubernetes部署Springboot或Nginx的详细教程
- python输入年份月份输出天数_6.2(输入年份 月份 输出该月天数)