最近要给Yahoo的同事们做一个关于PHP和Apache处理请求的内部机制的讲座,刚好写了些关于Opcodes的文字,就发上来了,这个文章基于 Sara Golemon大师的《Understanding OPcode》

Opcode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,或者.NET的MSL,举个例子,比如你写下了如下的PHP代码:

echo "Hello World";

$a = 1 + 1;

echo $a;

?>

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

1.Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)

2.Parsing, 将Tokens转换成简单而有意义的表达式

3.Compilation, 将表达式编译成Opocdes

4.Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。

题外话:现在有的Cache比如APC,可以使得PHP缓存住Opcodes,这样,每次有请求来临的时候,就不需要重复执行前面3步,从而能大幅的提高PHP的执行速度。

那什么是Lexing? 学过编译原理的同学都应该对编译原理中的词法分析步骤有所了解,Lex就是一个词法分析的依据表。 Zend/zend_language_scanner.c会根据Zend/zend_language_scanner.l(Lex文件),来输入的 PHP代码进行词法分析,从而得到一个一个的“词”,PHP4.2开始提供了一个函数叫token_get_all,这个函数就可以讲一段PHP代码 Scanning成Tokens;

如果用这个函数处理我们开头提到的PHP代码,将会得到如下结果:

Array

(

[0] => Array

(

[0] => 367

[1] => Array

(

[0] => 316

[1] => echo

)

[2] => Array

(

[0] => 370

[1] =>

)

[3] => Array

(

[0] => 315

[1] => "Hello World"

)

[4] => ;

[5] => Array

(

[0] => 370

[1] =>

)

[6] => =

[7] => Array

(

[0] => 370

[1] =>

)

[8] => Array

(

[0] => 305

[1] => 1

)

[9] => Array

(

[0] => 370

[1] =>

)

[10] => +

[11] => Array

(

[0] => 370

[1] =>

)

[12] => Array

(

[0] => 305

[1] => 1

)

[13] => ;

[14] => Array

(

[0] => 370

[1] =>

)

[15] => Array

(

[0] => 316

[1] => echo

)

[16] => Array

(

[0] => 370

[1] =>

)

[17] => ;

)

分析这个返回结果我们可以发现,源码中的字符串,字符,空格,都会原样返回。每个源代码中的字符,都会出现在相应的顺序处。而,其他的比如标签,操作符,语句,都会被转换成一个包含俩部分的Array: Token ID (也就是在Zend内部的改Token的对应码,比如,T_ECHO,T_STRING),和源码中的原来的内容。

接下来,就是Parsing阶段了,Parsing首先会丢弃Tokens Array中的多于的空格,然后将剩余的Tokens转换成一个一个的简单的表达式

1.echo a constant string

2.add two numbers together

3.store the result of the prior expression to a variable

4.echo a variable

1.Opcode数字的标识,指明了每个op_array的操作类型,比如add , echo然后就改Compilation阶段了,它会把Tokens编译成一个个op_array, 每个op_arrayd包含如下5个部分:

2.结果 存放Opcode结果

3.操作数1 给Opcode的操作数

4.操作数2

5.扩展值 1个整形用来区别被重载的操作符

比如,我们的PHP代码会被Parsing成:

* ZEND_ECHO 'Hello World'

* ZEND_ADD ~0 1 1

* ZEND_ASSIGN !0 ~0

* ZEND_ECHO !0

a)op_type : 为IS_CONST, IS_TMP_VAR, IS_VAR, IS_UNUSED, or IS_CV呵呵,你可能会问了,我们的$a去那里了?

恩,这个要介绍操作数了,每个操作数都是由以下俩个部分组成:

b)u,一个联合体,根据op_type的不同,分别用不同的类型保存了这个操作数的值(const)或者左值(var)

而对于var来说,每个var也不一样

IS_TMP_VAR, 顾名思义,这个是一个临时变量,保存一些op_array的结果,以便接下来的op_array使用,这种的操作数的u保存着一个指向变量表的一个句柄(整数),这种操作数一般用~开头,比如~0,表示变量表的0号未知的临时变量

IS_VAR 这种就是我们一般意义上的变量了,他们以$开头表示

IS_CV 表示ZE2.1/PHP5.1以后的编译器使用的一种cache机制,这种变量保存着被它引用的变量的地址,当一个变量第一次被引用的时候,就会被CV起来,以后对这个变量的引用就不需要再次去查找active符号表了,CV变量以!开头表示。

这么看来,我们的$a被优化成!0了。

php 编译原理,php编译原理 - Robin3D的个人页面 - OSCHINA - 中文开源技术交流社区相关推荐

  1. 泊松分酒 java课件_泊松分酒原理 - 我类个擦的个人空间 - OSCHINA - 中文开源技术交流社区...

    有一个12品脱(pint)的酒瓶,里面装满葡萄酒,另有8品脱和5品脱的瓶子各一个.问如何从中分出6品脱的酒出来? 传说泊松年轻时成功解决了该问题,勾起了他对数学的兴趣而投身数学研究,因此该问题被称为泊 ...

  2. 三个瓶子分酒c语言源码,泊松分酒原理 - 我类个擦的个人空间 - OSCHINA - 中文开源技术交流社区...

    有一个12品脱(pint)的酒瓶,里面装满葡萄酒,另有8品脱和5品脱的瓶子各一个.问如何从中分出6品脱的酒出来? 传说泊松年轻时成功解决了该问题,勾起了他对数学的兴趣而投身数学研究,因此该问题被称为泊 ...

  3. 重定向linux编译,linux重定向 - 悟性的个人页面 - OSCHINA - 中文开源技术交流社区...

    linux重定向: 0.1和2分别表示标准输入.标准输出和标准错误信息输出,可以用来指定需要重定向的标准输入或输出. 在一般使用时,默认的是标准输出,既1.当我们需要特殊用途时,可以使用其他标号.例如 ...

  4. noa格式转java_用IDEA查看反编译 - osc_1loi8uc4的个人空间 - OSCHINA - 中文开源技术交流社区...

    目录 一 找到java编译后的class文件 二 查看编译后的结果 发现是乱码 三 将字节码文件拷贝到IDEA中 四 打开这个class文件 下面这个结果就是IDEA反编译的结果 // // Sour ...

  5. python倒排索引实现_倒排索引原理和实现 - uncle_LLD的个人空间 - OSCHINA - 中文开源技术交流社区...

    关于倒排索引 搜索引擎通常检索的场景是:给定几个关键词,找出包含关键词的文档.怎么快速找到包含某个关键词的文档就成为搜索的关键.这里我们借助单词--文档矩阵模型,通过这个模型我们可以很方便知道某篇文档 ...

  6. java创建两个foo方法_Java类实例化原理 - osc_foo7glsg的个人空间 - OSCHINA - 中文开源技术交流社区...

    Java对象的创建过程包括类初始化(类实例化两个阶段. 一.Java对象创建时机 (1)使用new关键字创建对象 (2)反射创建对象 使用Class类的newInstance方法 Student st ...

  7. python读写磁盘扇区数据有什么用_磁盘存放数据原理 - osc_v8xs2czi的个人空间 - OSCHINA - 中文开源技术交流社区...

    磁盘结构作用数据原理 拓扑图 盘面(side) 模型: 1.磁盘圆形盘面,一个磁盘内含有多个盘面. 2.层叠关系,每个盘面之间不会贴着. 3.第一个盘的正面成为0面,反面为1面:第二个盘正面为2面,反 ...

  8. python编译 pyd 工具_avalon-fsn首页、文档和下载 - Python 编译构造工具 - OSCHINA - 中文开源技术交流社区...

    avalon-fsn avalon-fsn 是一个Python的编译构造工具,能够将你的代码Cython 使用avalon-fsn的好处 代码Cython化:Windows下把代码编译为pyd,Lin ...

  9. php 原理 淘口令 解密_淘口令解析 - super19911115的个人空间 - OSCHINA - 中文开源技术交流社区...

    淘口令解析 通过程序解析淘口令,无需联盟开发者权限,只需几行代码就可实现自动识别淘口令: def query_password(sign_server, share_password): data = ...

  10. 【实习周记】微信网络组件——腾讯Mars框架的原理、编译和使用

    腾讯mars框架的编译和使用 腾讯Mars框架的原理.编译和使用 一.Mars的编译 二.Mars的使用 1.初始化Mars 2.通过长连接发送消息 3.使用短链接发送 4.接收相应请求的返回消息 5 ...

最新文章

  1. (转)Silverlight显示本地图片、Stream转Byte数组
  2. 一位小小码蚁工作2年多感想
  3. 基于 DataLakeAnalytics 做跨地域的数据分析
  4. android手机打电话src,【SPILL 百科】SRC:Android 系统的 48kHz 音讯输出限制
  5. 组态王 6.55 启停plc_永宏PLC在远程控制系统中的应用
  6. 关于 spring MVC 配置自动扫描中 use-default-filters 属性
  7. 【MySQL】MySQL每秒统计一次showglobal status
  8. 开源SPL,ORM的终结者?
  9. 【TensorFlow实战】TensorFlow实现经典卷积神经网络之ResNet
  10. Android内容提供者(群发短信)
  11. 巧用MacOS的勿扰模式,解决广告弹窗
  12. Flink大数据计算的机遇与挑战
  13. vb access mysql_vb连接access数据库
  14. Flask+SQLAlchemy+graphene+docker示例
  15. RecyclerView自定义分割线实战
  16. Vmware中Linux 虚拟终端之间 无法切换 解决方法
  17. 群晖NAS的公网、NAT、DDNS、证书等配置一
  18. 中国人工智能领域企业分类(附未来企业排行)
  19. 文墨绘学书法教育领导品牌
  20. 港科夜闻|广州市市长郭永航先生与香港科大校董会廖长城先生一行举行座谈交流...

热门文章

  1. python 汽车行业数据库_python3+Neo4j+flask,汽车行业知识图谱项目实战
  2. You-Get—— 基于 Python3 的媒体下载工具
  3. JavaSE基础篇之-Java 流(Stream)、文件(File)和IO
  4. vue 获取安卓原生方法_H5-vue与原生Android、ios交互获取相册图片
  5. php无人点餐,东营_无人餐厅来了! 自助点餐、自动上菜 , 没有一个服务员!_胜利社区_东营论坛_油城茶座...
  6. 单片机r6/r7c语言怎么用,第5章MCU混合编程与C语言和汇编语言
  7. 使用Adorner显示WPF控件的边界点
  8. openstack pike版本安装笔记6(dashboard组件,控制台)
  9. L2-004. 这是二叉搜索树吗?
  10. 小米2系列板砖自救行动