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

[经验分享] PHP解释器引擎执行流程

[复制链接]

尚未签到

发表于 2017-3-29 10:41:36 | 显示全部楼层 |阅读模式
  这里将介绍引擎内部执行一个PHP脚本的流程,以cli SAPI为例子来对流程中核心的部分做简单介绍,省去一些初始化及清理操作。
    CLI(Command Line Interface)即PHP的命令行模式,现在此SAPI是默认安装的,我们在服务器上安装完PHP之后,一般会生成一个可执行文件,假设此文件为/usr/local/bin/php ,那么我们在SHELL下可以用以下命令来执行一个PHP脚本:
/usr/local/bin/php -f test.php
这个命令将执行当前目录下的test.php脚本,我们暂且不关心test.php具体内容,只关心一下这个执行的内部过程是怎么样的。
  
      CLI的主源代码文件在{PHPSRC}/sapi/cli/php_cli.c,整个过程就从这个文件中的 main()函数执行,整个函数比较长,主要可以分为以下几个阶段:
1:解析命令行参数
2:初始化环境
3:编译执行PHP代码
4:清理环境并返回退出
  
在第1个阶段中,解析-f参数为执行一个PHP文件,-f后面的test.php就是需要被执行的文件
这里我们将关注第3个阶段,如何执行test.php中的PHP代码。
最终是通过php_execute_script(&file_handle TSRMLS_CC)来执行PHP的脚本,这个函数定义在{PHPSRC}/main/main.c,原型为:
PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC) 
file_handle的类型为zend_file_handle,这个是zend对文件句柄的一个封装,里面的内容就是和test.php相关的了。

php_execute_script最终是调用的zend_execute_scripts,这个函数定义在{PHPSRC}/Zend/zend.c,原型为:
ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_count, ...) 
此函数具有可变参数,可以一次执行多个PHP文件,在此函数中最核心的是调用zend_compile_file和zend_execute,
  zend_compile_file是一个函数指针,其声明在{PHPSRC}/Zend/zend_compile.c:
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);  在引擎初始化的时候,会将compile_file函数的地址赋值给zend_compile_file,compile_file函数定义在{PHPSRC}/Zend/zend_language_scanner.c,通过声明可以看到这个函数以zend_file_handle指针作为参数,返回一个指向zend_op_array的指针。
  
zend_execute也是一个函数指针,其声明在{PHPSRC}/Zend/zend_execute.c:
ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC); 
同样在引擎初始化的时候,会将execute函数的地址赋值给zend_execute,execute的定义在{PHPSRC}/Zend/zend_vm_execute.h。
通过声明知道zend_execute以一个指向zend_op_array结构的指针作为参数,这个指针即前面zend_compile_file的返回值,zend_execute就开始执行op_array中的op code,在执行op code的过程中,就实现了PHP语言的各种功能。
  到这里主要的执行工作基本就完成。
  PS:
  为什么要把zend_execute和zend_compile_file定义为函数指针?
  在引擎初始化(zend_startup)的时候,将zend_execute指向了默认的execute,zend_compile_file指向了默认的compile_file。我们可以在实际编译和执行之前将zend_execute和zend_compile_file重写为其他的编译和执行函数,这样就为我们扩展引擎留下了钩子,比如一个比较有名的查看PHP的op code的扩展vld(http://www.derickrethans.nl/projects.html#vld),此扩展就是在每次请求初始化的钩子函数(PHP_RINIT_FUNCTION)中,将zend_execute和zend_compile_file替换成自己的vld_execute和vld_compile_file,这两个函数其实是对原始函数进行了封装,添加了输出opcode信息的附加功能,因为引擎初始化是发生在模块请求初始化之前,而模块请求初始化又是在编译和执行之前,所以这样的覆盖能达到目的。
  原文地址: http://blog.csdn.net/phpkernel/article/details/5716342

运维网声明 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-356943-1-1.html 上篇帖子: PHP数据库树的遍历方法 下篇帖子: 高手讲解PHP遍历数组的方法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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