为了账号安全,请及时绑定邮箱和手机立即绑定

PHP的底层执行原理和周期

标签:
PHP
  1. PHP执行周期
    首先,Zend Engine(ZE),调用词法分析 器(Lex生成的,源文件在 Zend/zend_language_sanner.l), 将我们要执行的PHP源文件,去掉空格 ,注释,分割成一个一个的token。
    然后,ZE会将得到的token forward给语法分析 器(yacc生成, 源文件在 Zend/zend_language_parser.y),生成一个一个的opcode,opcode一般会以op array的形式存在,它是PHP执行的中间语言。
    最后,ZE调用zend_executor来执行op array ,输出结果。(也就是将源文件转换成机器语言,然后在虚拟机上运行它。)
    ZE是一个虚拟机,正是由于它的存在,所以才能使得我们写PHP脚本,完全不需要考虑所在的操作系统类型是什么,这才是PHP的可移植性的原因。ZE是一个CISC(复杂指令处理器),它支持150条指令(具体指令在 Zend/zend_vm_opcodes.h),包括从最简单的ZEND_ECHO(echo)到复杂的 ZEND_INCLUDE_OR_EVAL(include,require),所有我们编写的PHP都会最终被处理为这150条指令(op code)的序列,从而最终被执行。
  2. opcode长怎么样子
    在PECL中已经有这样的模块,利用由 Derick Rethans开发的VLD (Vulcan Logic Dissassembler)模块。你只要下载这个模块,并把他载入PHP中,就可以通过简单的设置,来得到脚本翻译的结果了。
    [root@localhost software]# tar zxvf vld-0.9.1.tgz.gz
    [root@localhost vld-0.9.1]# /usr/local/php/bin/phpize
    [root@localhost vld-0.9.1]# ./configure --with-php-config=/usr/local/php/bin/php-config
    [root@localhost vld-0.9.1]# make install //不需要make

[root@localhost html]# vi vld.php
<?php
$i = "This is a string";
//I am comments
echo $i. ' that has been echoed on screen';
?>

[root@localhost html]# /usr/local/php/bin/php -dvld.active=1 vld.php
Branch analysis from position: 0
Return found
filename: /var/www/html/vld.php
function name: (null)
number of ops: 5
compiled vars: !0 = $i
line # op fetch ext return operands

3 0 ASSIGN !0, 'This+is+a+string'
7 1 CONCAT ~1 !0, '+that+has+been+echoed+on+screen'
2 ECHO ~1
10 3 RETURN 1
4 ZEND_HANDLE_EXCEPTION
This is a string that has been echoed on screen
注:ZEND_HANDLE_EXCEPTION 就是 Zend/zend_vm_opcodes.h 中第149条指令
compiled vars: !0 = $i 此处是获取变量名"i"的变量于!0(
zval)。

0 将字符串"this+is+a+string"赋值(ASSIGN)给!0
1 字符串连接
2 显示

这些中间代码会被Zend VM(Zend虚拟机)直接执行。真正负责执行的函数是:zend_execute(zend_execute.h)。

3 PHP核心组成部分
SAPI: 这是PHP与Web服务器交互的接口,包括运行模式是cli或者是cgi。
PHP扩展: 完成数据库调用,数据交换,数据加密等脚本大部分功能。
PHP内核: php内核获取服务器传递的环境变量信息,调用PHP函数,类,扩展模块,统筹PHP运行,为编译工作做准备。
Zend虚拟机: 完成词法分析,语法分析,语义分析,中间代码生成,代码优化,目标代码生成等核心功能,负责PHP代码编译执行。

4PHP执行前后发生的事情
PHP开始执行以后会经过两个主要的阶段:处理请求之前的开始阶段和请求之后的结束阶段。
开始阶段有两个过程:
第一个过程是模块初始化阶段(MINIT), 在整个SAPI生命周期内(例如Apache启动以后的整个生命周期内或者命令行程序整个执行过程中), 该过程只进行一次。
第二个过程是模块激活阶段(RINIT),该过程发生在请求阶段, 例如通过url请求某个页面,则在每次请求之前都会进行模块激活(RINIT请求开始)。
例如PHP注册了一些扩展模块,则在MINIT阶段会回调所有模块的MINIT函数。 模块在这个阶段可以进行一些初始化工作,例如注册常量,定义模块使用的类等等。
请求到达之后PHP初始化执行脚本的基本环境,例如创建一个执行环境,包括保存PHP运行过程中变量名称和值内容的符号表, 以及当前所有的函数以及类等信息的符号表。然后PHP会调用所有模块的RINIT函数, 在这个阶段各个模块也可以执行一些相关的操作
请求处理完后就进入了结束阶段,一般脚本执行到末尾或者通过调用exit()或die()函数, PHP都将进入结束阶段。和开始阶段对应,结束阶段也分为两个环节,一个在请求结束后停用模块(RSHUTDOWN,对应RINIT), 一个在SAPI生命周期结束(Web服务器退出或者命令行脚本执行完毕退出)时关闭模块(MSHUTDOWN,对应MINIT)。图片描述

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消