PHP代码的执行

本文涉及的产品
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 先看下PHP的结构图

先看下PHP的结构图:

image.png


1)Zend Engine

Zend引擎是PHP实现的核心,提供了语言实现上的基础设施。例如:PHP的语法实现,脚本的编译运行环境, 扩展机制以及内存管理等。

2)Extensions

围绕着zend引擎,Extensions通过组件式的方式提供各种基础服务,我们常见的各种内置函数(如MySQL系列)、标准库等都是通过Extension来实现,用户也可以根据需要实现自己的extension以达到功能扩展、性能优化等目的。

3)SAPI

SAPI(Server Application Programming Interface)指的是PHP具体应用的编程接口。就像PC一样,无论安装哪些操作系统,只要满足了PC的接口规范都可以在PC上正常运行。

4)架构思想

如果php是一辆车,那么车的框架就是php本身,Zend是车的引擎(发动机),Ext下面的各种组件就是车的轮子,SAPI可以看做是公路,车可以跑在不同类型的公路上,而一次php程序的执行就是汽车跑在公路上。因此,我们需要:性能优异的引擎+合适的车轮+正确的跑道。

 

一、Apache


Apache是Apache软件基金会的一个开放源代码的Web服务器,Apache支持许多特性,大部分通过模块扩展实现。

常见的模块包括mod_auth(权限验证)、mod_ssl(SSL和TLS支持) mod_rewrite(URL重写)等。

下图为Apache的逻辑构成以及与操作系统的关系:


image.png


 

1)Apache的mod_php5模块

当PHP需要在Apache服务器下运行时,可以用mod_php5模块的形式集成。

此时mod_php5模块的作用是接收Apache传递过来的PHP文件请求,并处理这些请求, 然后将处理后的结果返回给Apache。

 

2)Apache的运行过程

Apache的运行分为启动阶段和运行阶段。

在运行阶段,Apache主要工作是处理用户的服务请求。

Apache对HTTP的请求可以分为连接、处理和断开连接三个大的阶段。同时也可以分为11个小的阶段:

Post-Read-Request,URI Translation,Header Parsing,Access Control,Authentication,

Authorization,MIME Type Checking,FixUp,Response,Logging,CleanUp。


image.png

 

3)Apache Hook机制


模块可以在Apache的任何一个处理阶段中挂接(Hook)上自己的处理函数,从而参与Apache的请求处理过程。

 

二、FastCGI


1)CGI

  CGI全称是“通用网关接口”(Common Gateway Interface),描述了客户端和服务器程序之间传输数据的一种标准。它可以让一个客户端,从网页浏览器向执行在Web服务器上的程序请求数据。CGI用来沟通程序(如PHP, Python, Java)和Web服务器(Apache2, Nginx),理论上任何语言编写的程序都可以通过CGI来提供Web服务。

  比如现在请求的是“index.php”,根据配置文件,Apache知道这个不是静态文件,需要去找PHP解析器来处理,那么它会把这个请求简单处理后交给PHP解析器。Apache会传url、查询字符串、POST数据、HTTP header等,而CGI就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的协议。

  当web服务器收到“index.php”这个请求后,会启动对应的CGI程序,这里就是PHP的解析器。接下来PHP解析器会解析php.ini、载入全部扩展并初始化全部数据结构,然后处理请求,再以CGI规定的格式返回处理后的结果,退出进程,web服务器再把结果返回给浏览器。


image.png


 

2)FastCGI

  CGI程序存在性能问题,每次请求都会重复“PHP解析器会解析php.ini、载入全部扩展并初始化全部数据结构”这些步骤。

  FastCGI是CGI的一种改进方案。FastCGI像是一个常驻(long-live)型的CGI, 它可以一直执行,在请求到达时不会花费时间去fork一个进程来处理(这是CGI最为人诟病的fork-and-execute模式)。

FastCGI工作流程的通俗版本如下:

1. Fastcgi会先启一个master,解析配置文件,初始化执行环境,然后再启动多个worker。

2. 当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然是高。

3. 当worker不够用时,master可以根据配置预先启动几个worker等着。

4. 当空闲worker太多时,也会停掉一些,这样就提高了性能,也节约了资源。

FastCGI工作流程的专业版本如下:

1. Web Server启动时载入FastCGI进程管理器(IIS ISAPI或Apache Module)

2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。

3. 当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。

4. FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时, 请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中,php-cgi在此便退出了。

image.png


3)PHP-CGI

PHP-CGI是PHP自带的FastCGI管理器。

PHP-CGI的不足:

1. php-cgi变更php.ini配置后需重启php-cgi才能让新的php-ini生效,不可以平滑重启。

2. 直接杀死php-cgi进程,php就不能运行了。(PHP-FPM和Spawn-FCGI就没有这个问题,守护进程会平滑从新生成新的子进程。)


4)PHP-FPM

PHP-FPM是一个PHP FastCGI管理器,是只用于PHP的。

PHP-FPM其实是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中。必须将它patch到你的PHP源代码中,在编译安装PHP后才可以使用。

 

三、SAPI


下图为SAPI的简单示意图:


image.png


SAPI(Server abstraction API),它提供了一个接口,使得PHP可以和其他应用进行交互数据。

 

1)PHP执行的两个阶段,开始和结束

开始阶段:

a. 模块初始化阶段(MINIT), 在整个SAPI生命周期内(例如Apache启动以后的整个生命周期内或者命令行程序整个执行过程中), 该过程只进行一次

b. 模块激活阶段(RINIT),该过程发生在请求阶段, 例如通过url请求某个页面,则在每次请求之前都会进行模块激活(RINIT请求开始)

结束阶段:

a. 停用模块(RSHUTDOWN,对应RINIT)

b. 在SAPI生命周期结束(Web服务器退出或者命令行脚本执行完毕退出)时关闭模块(MSHUTDOWN,对应MINIT)

 

2)单进程SAPI生命周期

CLI/CGI模式的PHP属于单进程的SAPI模式。这类的请求在处理一次请求后就关闭。也就是只会经过如下几个环节:

开始 - 请求开始 - 请求关闭 - 结束。SAPI接口实现就完成了其生命周期。

a. 启动:初始化若干全局变量,初始化若干常量,初始化Zend引擎和核心组件,解析php.ini,全局操作函数的初始化,初始化静态构建的模块和共享模块(MINIT),禁用函数和类

b. 激活:激活Zend引擎,激活SAPI,环境初始化,模块请求初始化

c. 运行:要解析执行的文件,需要做词法分析、语法分析和中间代码生成操作,返回此文件的所有中间代码

d. 关闭:关闭请求的过程是一个若干个关闭操作的集合

e. 结束:flush,关闭Zend引擎

 

3)多进程SAPI生命周期

通常PHP是编译为apache的一个模块来处理PHP请求。

  Apache一般会采用多进程模式, Apache启动后会fork出多个子进程,每个进程的内存空间独立,每个子进程都会经过开始和结束环节, 不过每个进程的开始阶段只在进程fork出来以来后进行,在整个进程的生命周期内可能会处理多个请求。


image.png

 

4)多线程的SAPI生命周期


  多线程模式和多进程中的某个进程类似,不同的是在整个进程的生命周期内会并行的重复着 请求开始-请求关闭的环节


image.png


 

四、PHP脚本的执行


SAPI处于PHP整个架构较上层,而真正脚本的执行主要由Zend引擎来完成。


<?php
$str = "Hello, World!\n";
echo $str;


a. 如上例中, 传递给php程序需要执行的文件, php程序完成基本的准备工作后启动PHP及Zend引擎, 加载注册的扩展模块。

b. 初始化完成后读取脚本文件,Zend引擎对脚本文件进行词法分析,语法分析。

c. 编译成opcode执行。 如果安装了apc之类的opcode缓存, 编译环节可能会被跳过而直接从缓存中读取opcode执行。



image.png


很多编程语言都使用lex/yacc或他们的变体(flex/bison)来作为语言的词法语法分析生成器, 比如PHP、Ruby、Python以及MySQL的SQL语言实现。

PHP是构建在Zend虚拟机(Zend VM)之上的。PHP的opcode就是Zend虚拟机中的指令。

 


相关文章
|
17小时前
|
存储 运维 Serverless
函数计算产品使用问题之在YAML文件中配置了环境变量,但在PHP代码中无法读取到这些环境变量,是什么原因
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
2天前
|
XML Ubuntu 机器人
教你如何提高 PHP 代码的质量
教你如何提高 PHP 代码的质量
|
4天前
|
XML 前端开发 JavaScript
高质量的PHP代码的技巧
高质量的PHP代码的技巧
|
4天前
|
XML 关系型数据库 MySQL
php常用代码分享
php常用代码分享
|
4天前
|
XML 前端开发 API
分享好用便捷的 PHP 代码
21 段实用便捷的 PHP 代码
|
1月前
|
PHP 数据库 开发者
PHP中的异常处理:提升代码稳定性的关键
【5月更文挑战第27天】在软件开发中,异常处理是一种重要的错误管理技术。它允许开发者优雅地处理运行时出现的错误,而不是让程序崩溃。本文将深入探讨PHP中的异常处理机制,包括异常的基本概念,如何抛出和捕获异常,以及如何使用自定义异常类。通过理解和应用这些概念,开发者可以编写出更健壮、更稳定的代码。
|
1月前
|
PHP 开发者
深入PHP命名空间:代码模块化和避免冲突
【5月更文挑战第26天】在现代PHP开发中,命名空间是实现代码模块化、防止类名和函数名冲突的关键技术。本文将深入探讨PHP命名空间的概念、实现原理及其在实际项目中的应用,帮助开发者更好地理解和使用命名空间,提高代码的可维护性和可扩展性。
|
1月前
|
PHP
利用一段代码轻松绕过PHP授权系统
利用一段代码轻松绕过PHP授权系统
29 0
|
1月前
|
PHP 开发者
【专栏】介绍PHP的命名空间,它是一个用于封装代码、避免名称冲突的机制
【4月更文挑战第27天】本文介绍了PHP的命名空间,它是一个用于封装代码、避免名称冲突的机制。命名空间的作用包括:防止大型项目中的命名冲突,提升代码可读性和可维护性,以及方便代码重用。文章详细阐述了如何定义、导入命名空间,使用完全限定名称以及设置命名空间别名。通过实例展示了命名空间在项目模块划分和第三方库如Laravel中的应用,强调了命名空间在组织和管理PHP代码中的关键作用。
|
1月前
|
安全 PHP 开发工具
php代码加密 php-screw-plus
php代码加密 php-screw-plus
53 0