设为首页 收藏本站
查看: 797|回复: 0

[经验分享] Understanding PHP Opcode (Forward)

[复制链接]

尚未签到

发表于 2017-3-24 12:38:23 | 显示全部楼层 |阅读模式
  《Understanding OPcode》
Opcode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,或者.NET的MSL,举个例子,比如你写下了如下的PHP代码:


  • <?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
  然后就改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_CV
  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了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-354674-1-1.html 上篇帖子: windows下安装 memcache + php 下篇帖子: Understanding PHP Opcode (Forward)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表