理解php原理的opcodes(操作码)


Posted in PHP onOctober 26, 2010

Opcondes是一种php脚本编译后的中间语言,就像Java的Byte Code,或者.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的执行速度。 ” 这可能是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

然后就改Compilation阶段了,它会把Tokens编译成一个个op_array, 每个op_arrayd包含如下5个部分:
1.Opcode数字的标识,指明了每个op_array的操作类型,比如add , echo 
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去那里了?

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

a)op_type : 为IS_CONST, IS_TMP_VAR, IS_VAR, IS_UNUSED, or IS_CVb)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了。
总结:

1.php的执行顺序是: -> php程序

-> 被Scanning(扫描转换为Tokens(语言片段))

-> 被Parsing(语法分析,将Tokens转换成简单而有意义的表达式)

-> Compilation(编译,将表达式编译成Opocdes(操作码))
-> Execution(顺序执行编译后的结果)
2. APC(Alternative PHP Cache)的缓存机制可以缓存住Opcodes,这样,下次有请求来临的时候,就不需要重复执行前面3步,从而能大幅的提高PHP的执行速度。 这可能是php执行速度比较快的原因之一

补充:
apc,zend optimize是之所以能够加速php
就是因为他可以缓存opcode
并不是zend引擎本身自带的功能
zend引擎默认是一个轮回中任何一项都要走的

PHP 相关文章推荐
自己动手做一个SQL解释器
Oct 09 PHP
php录入页面中动态从数据库中提取数据的实现
Oct 09 PHP
模仿OSO的论坛(四)
Oct 09 PHP
WindowsXP中快速配置Apache+PHP5+Mysql
Jun 05 PHP
PHP导入Excel到MySQL的方法
Apr 23 PHP
PHP5中新增stdClass 内部保留类
Jun 13 PHP
php 记录进行累加并显示总时长为秒的结果
Nov 04 PHP
微信公众号点击菜单即可打开并登录微站的实现方法
Nov 14 PHP
php+xml编程之SimpleXML的应用实例
Jan 24 PHP
php中curl使用指南
Feb 05 PHP
PHP实现的迪科斯彻(Dijkstra)最短路径算法实例
Sep 16 PHP
让你的PHP,APACHE,NGINX支持大文件上传
Mar 09 PHP
PHP下常用正则表达式整理
Oct 26 #PHP
PHP编程最快明白(第一讲 软件环境和准备工作)
Oct 25 #PHP
微盾PHP脚本加密专家php解密算法
Sep 13 #PHP
smarty中先strip_tags过滤html标签后truncate截取文章运用
Oct 25 #PHP
php正则过滤html标签、空格、换行符的代码(附说明)
Oct 25 #PHP
PHP 强制下载文件代码
Oct 24 #PHP
php下网站防IP攻击代码,超级实用
Oct 24 #PHP
You might like
用php或asp创建网页桌面快捷方式的代码
2010/03/23 PHP
thinkPHP实现表单自动验证
2014/12/24 PHP
goto语法在PHP中的使用教程
2020/09/17 PHP
仿163填写邮件地址自动显示下拉(无优化)
2008/11/05 Javascript
如何使用Javascript获取距今n天前的日期
2013/07/08 Javascript
jQuery怎么解析Json字符串(Json格式/Json对象)
2013/08/09 Javascript
JQuery的$命名冲突详细解析
2013/12/28 Javascript
js实现div弹出层的方法
2014/11/20 Javascript
JavaScript中的方法调用详细介绍
2014/12/30 Javascript
JavaScript给url网址进行encode编码的方法
2015/03/18 Javascript
js数组依据下标删除元素
2015/04/14 Javascript
使用requestAnimationFrame实现js动画性能好
2015/08/06 Javascript
JS+CSS实现简易的滑动门效果代码
2015/09/24 Javascript
Mui使用jquery并且使用点击跳转新窗口的实例
2017/08/19 jQuery
关于axios不能使用Vue.use()浅析
2018/01/12 Javascript
vue中v-for循环给标签属性赋值的方法
2018/10/18 Javascript
从零撸一个pc端vue的ui组件库( 计数器组件 )
2019/08/08 Javascript
python求列表交集的方法汇总
2014/11/10 Python
pygame学习笔记(3):运动速率、时间、事件、文字
2015/04/15 Python
使用rst2pdf实现将sphinx生成PDF
2016/06/07 Python
Python嵌套列表转一维的方法(压平嵌套列表)
2018/07/03 Python
django query模块
2019/04/20 Python
利用Python检测URL状态
2019/07/31 Python
在Python3 numpy中mean和average的区别详解
2019/08/24 Python
opencv调整图像亮度对比度的示例代码
2019/09/27 Python
Django nginx配置实现过程详解
2020/09/10 Python
Python3如何使用range函数替代xrange函数
2020/10/05 Python
HTML5 Canvas实现360度全景图的示例代码
2018/01/29 HTML / CSS
Hanro官网:奢华男士和女士内衣、睡衣和家居服
2018/10/25 全球购物
CHARLES & KEITH澳大利亚官网:新加坡时尚品牌
2019/01/22 全球购物
英国最受欢迎的母婴精品品牌:JoJo Maman BéBé
2021/02/17 全球购物
.net面试题
2016/09/17 面试题
某公司的.net工程师面试题笔试题
2013/11/22 面试题
结婚仪式主持词
2015/06/29 职场文书
教你怎么用Python生成九宫格照片
2021/05/20 Python
使用python绘制横竖条形图
2022/04/21 Python