深入理解PHP内核——PHP脚本执行的生命周期

PHP代码运行流程图

当用户代码输入给PHP内核去执行的时候, PHP内核会对PHP代码进行词法分析和语法分析, 词法分析是把PHP代码分割成一个个的“单元”(TOKEN), 语法分析则将这些“单元”转化为Zend Engine可执行的操作。 然后PHP内部的Zend Engine对这些操作进行顺次的执行。
Zend Engine是PHP内核的核心部分,负责最终操作的执形和结果的返回, 可以理解成为PHP内核中的“发动机”。
在这里插入图片描述

SAPI简介

通常,我们使用Apache或者Nginx这类Web服务器来运行PHP脚本,或者在命令行下通过PHP解释器程序来执性。 脚本执行完后,Web服务器应答,浏览器显示应答信息,或者在命令行标准输出上显示内容。
SAPI(Server Application Programming Interface)指的是PHP具体应用场景下的编程接口,PHP脚本要执行有很多种方式,通过Web服务器,或者直接在命令行下,也可以嵌入在其他程序中。每种不同的执行方式都对应一个具体的SAPI实现。
在这里插入图片描述

整个SAPI类似于一个面向对象中的模板方法模式的应用。 SAPI.c和SAPI.h文件所包含的一些函数就是模板方法模式中的抽象模板, 各个服务器对于sapi_module的定义及相关实现则是一个个具体的模板。
脚本执行过程中,不同的SAPI接口实现会完成它们特定的工作。

单进程SAPI的命周期

CLI/CGI模式的PHP属于单进程的SAPI模式。这类的请求在处理一次请求后就关闭。也就是只会经过如下几个环节: 开始 - 请求开始 -运行- 请求关闭 - 结束
CLI:命令行
CGI:CGI全称是“通用网关接口”(Common Gateway Interface),它可以让一个客户端,从网页浏览器向执行在Web服务器上的程序请求数据。CGI描述了客户端和这个程序之间传输数据的一种标准。
在这里插入图片描述

启动(开始)

  • 初始化若干全局变量、常量
  • 初始化Zend引擎和核心组件,包括内存管理初始化、 全局使用的函数指针初始化(对PHP源码件进性词法分析、语法分析、 中间代码执性的函数指针的赋值)
  • 解析php.ini,设置配置参数
  • 注册并初始化静态构建的模块和共享模块(MINIT)

ACTIVATION(请求开始)

  • 激活Zend引擎,初始化编译器、中间代码执行器。
  • 激活SAPI,完成他们特定的准备工作。
  • 环境初始化,包括服务器环境、请求数据环境等。 实际到我们用到的变量,就是 P O S T 、 _POST、 POST_GET、 C O O K I E 、 _COOKIE、 COOKIE_SERVER、 E N V 、 _ENV、 ENV_FILES
  • 模块的请求初始化(RINIT

运行

做词法分析、语法分析和中间代码生成操作,返回此文件的所有中间代码。 如果解析的文件有生成有效的中间代码,则执行中间代码。 如果在执行过程中出现异常并且用户有定义对这些异常的处理,则调用这些异常处理函数。 在所有的操作都处理完后,返回结果。

DEACTIVATION(请求关闭)

PHP关闭请求的过程是一个若干个关闭操作的集合,这个集合包括如下内容:

  • 调用所有通过register_shutdown_function()注册的函数。
  • 执行所有可用的__destruct函数。这里的析构函数包括在对象池(EG(objects_store)中的所有对象的析构函数以及EG(symbol_table)中各个元素的析构方法。
  • 将所有的输出刷出去。
  • 发送HTTP应答头。这也是一个输出字符串的过程,只是这个字符串可能符合某些规范。
  • 遍历每个模块的关闭请求方法,执行模块的请求关闭操作。
  • 销毁全局变量表的变量
  • 关闭词法分析器、语法分析器和中间代码执行器。
  • 调用每个扩展的post-RSHUTDOWN函数(RSHUTDOWN
  • 关闭SAPI
  • 关闭流的包装器、过滤器
  • 关闭内存管理
  • 重新设置最大执行

结束

  • sapi_flush将最后的内容刷新出去。在CLI模式下等价于fflush函数。
  • 关闭Zend引擎,执⾏每个模块的关闭模块操作(MSHUTDOWN
  • 在关闭所有的模块后,PHP继续销毁全局函数表,销毁全局类表、销毁全局变量表等。

多进程SAPI生命周期

通常PHP是编译为apache的一个模块来处理PHP请求。Apache一般会采用多进程模式, Apache启动后会fork出多个子进程,每个进程的内存空间独立,每个子进程都会经过开始和结束环节, 不过每个进程的开始阶段只在进程fork出来以来后进行,在整个进程的生命周期内可能会处理多个请求。 只有在Apache关闭或者进程被结束之后才会进行关闭阶段,在这两个阶段之间会随着每个请求重复请求开始-请求关闭的环节。
在这里插入图片描述

多线程的SAPI声明周期

多线程模式和多进程中的某个进程类似,不同的是在整个进程的生命周期内会并行的重复着请求开始-执行-请求关闭的环节。
在这里插入图片描述

FastCGI

CGI 简介

CGI全称是“通用网关接口”(Common Gateway Interface),它可以让一个客户端,从网页浏览器向执行在Web服务器上的程序请求数据。CGI描述了客户端和这个程序之间传输数据的一种标准。 CGI的一个目的是要独立于任何语言的,所以CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。 如php,perl,tcl等。

CGI的运行原理

在这里插入图片描述

FastCGI 简介

在这里插入图片描述

FastCGI 的作流程如下

在这里插入图片描述
在这里插入图片描述

FastCGI 与传统 CGI 模式的区别之一则是 Web 服务器不是直接执行 CGI 程序了,而是通过 Socket 与 FastCGI 响应器(FastCGI 进程管理器)进行交互,也正是由于 FastCGI 进程管理器是基于 Socket 通信的,所以也是分布式的,Web 服务器可以和 CGI 响应器服务器分开部署。Web 服务器需要将数据 CGI/1.1 的规范封装在遵循 FastCGI 协议包中发送给 FastCGI 响应器程序。

PHP中的CGI实现

在这里插入图片描述
在这里插入图片描述

编译型语言 VS 解释性语言

目前编程语言可以分为两大类:

  • 第一类是像C/C++, .NET, Java之类的编译型语言, 它们的共性是:运行之前必须对源代码进行编译,然后运行编译后的目标文件。
    第二类比如:PHP, Javascript, Ruby, Python这些解释型语言, 他们都无需经过编译即可"运行"。
    虽然可以理解为直接运行,但它们并不是真的直接就被能被机器理解, 机器只能理解机器语言,那这些语言是怎么被执行的呢, 一般这些语言都需要一个解释器,由解释器来执行这些源码, 实际上这些语言还是会经过编译环节, 只不过它们一般会在运行的时候实时进行编译。为了效率,并不是所有语言在每次执行的时候都会重新编译一遍, 比如PHP的各种opcode缓存扩展(如APC, xcache, eAccelerator等),比如Python会将编译的中间文件保存成pyc/pyo文件, 避免每次运行重新进行编译所带来的性能损失。

内容源自:《TIPI_深入理解PHP内核》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值