PHP的目录结构、设计理念以及核心架构
前一节:使用ext_skel,实现一个PHP扩展,试着使用 ext_skel
写了一个扩展,通过上一节可以大体了解自己如何写一个扩展。这一节主要介绍一下PHP的目录结构、设计理念以及核心架构。
一、PHP的目录结构
PHP源代码还包括在开发过程中生成的几个文件,以及在上游各自位置进行维护的几个部分。(注:PHP版本7.4.13)
1 | <php-src>/ |
目录 | 说明 |
---|---|
TSRM | 线程相关安全的实现,PHP的线程安全是构建在TSRM库之上的,PHP实现中常见的*G宏通常是对TSRM的封装,TSRM(Thread Safe Resource Manager)线程安全资源管理器。 |
Zend | PHP解析器的核心实现,比如脚本的词法语法解析,opcode的执行以及扩展机制的实现等 |
build | linux下编译相关的目录 |
ext | PHP的扩展,包括了绝大多数PHP的函数的定义和实现,如array系列,pdo系列,spl系列等函数的实现,都在这个目录中。个人写的扩展在测试时也可以放到这个目录,方便测试和调试。 |
main | PHP的主要代码,这里存放PHP最为核心的文件,主要实现PHP的基本设施,这里和Zend引擎不一样,Zend引擎主要实现语言最核心的语言运行环境。 |
netware | 网络目录,socket的定义与实现 |
pear | PHP扩展及应用的代码仓库,包含PEAR的核心文件。PEAR是PHP扩展与应用库(the PHP Extension and Application Repository)的缩写。它是一个PHP扩展及应用的一个代码仓库,简单地说,PEAR之于PHP就像是CPAN(Comprehensive Perl Archive Network)之于Perl。 |
sapi | PHP的应用层接口,包含了各种服务器抽象层的代码,例如apache的mod_php,cli,cgi,embed以及fpm等接口。 |
scripts | Linux下的脚本目录 |
tests | 测试脚本目录,包含PHP各项功能的测试文件 |
travis | 用于构建,非PHP特有目录 |
win32 | Windows下编译PHP的相关脚本,比如sokcet的实现在Windows下和*Nix平台就不太一样,同时也包括了Windows下编译PHP相关的脚本。 |
虽然源码目录众多,但是核心目录却只有sapi、main、zend、ext、TSRM。
1、SAPI
PHP程序的输入可以是来自于命令行的标准输入,也可以是来自基于cgi/fastcgi协议的网络请求。甚至可以嵌入到单片机供C、C++程序调用。它们分别对应cli模式、fpm/cgi模式、embed模式,除了这些还有apache2handler、litespeed模式。
sapi目录是对输入和输出层的抽象,是PHP提供对外服务的规范。
同理,输出可以写到命令行的标准输出,也可以作为基于cgi/fastcgi协议的网络响应返回给客户端。
SAPI全称Server API,负责PHP对外提供服务规范,它定义了结构体sapi_module_struct
,该结构体定义了模式启动、关闭、激活、失效等多个钩子函数指针,每个模式将这些函数指针指向自己的函数,就可以轻松扩展PHP对外服务的方式。以上几种模式也正是实现了sapi_module_strcut才完成了PHP的多场景应用。
几种常用的SAPI:
(1)、apache2handler:Apache扩展,编译后生成动态链接库,配置到Apache下,当有http请求到Apache时,根据配置会调用此动态链接库,执行PHP代码,完成与PHP的交互。
(2)、cgi-fcgi:编译后生成支持CGI协议的可执行程序,webserver(通常为Apache或Nginx)通过CGI协议把请求传给CGI进程,执行代码将结果返回给webserver,退出进程。
(3)、fpm-fcgi:fpm全称为FastCGI Process Manager,PHP官方提供的FastCGI进程管理器。以Nginx服务器为例,当有http协议请求发送到Nginx服务器,Nginx按照FastCGI协议把请求交给php-fpm进程处理。
(4)、cli:Command Line Interface的简称,PHP的命令行交互接口。
2、main
main目录是SAPI层和Zend层的黏合剂。
main目录的作用是承接SAPI的请求,分析出要执行的脚本文件和参数,并对环境和配置进行初始化,比如初始化变量和常量、注册函数、解析配置文件、加载扩展等等。
3、Zend
Zend目录就是大家所熟知的Zend引擎,是PHP最核心的部分,主要负责PHP的语法实现、内存管理及脚本的编译运行环境等,它由编译器、执行器两部分组成。
编译器负责将PHP代码进行词法、语法分析,并生成抽象语法树,然后进一步编译为opcode,opcode是Zend虚拟机可识别的指令,php7一共有173个opcode,所有的语法都是由这些opcode组成的。执行器负责执行编译器输出的opcode。
4、ext
ext(extension),它是扩展PHP内核功能的一种方式,分为PHP扩展与zend扩展,都支持用户自定义开发,这两种都比较常见,PHP扩展有gd、json、date、array等,而我们熟知的opcache就是Zend扩展。
上一节使用ext_skel,实现一个PHP扩展 写的自定义扩展就放在此目录下。
5、TSRM
TSRM(Thread Safe Resource Manager)线程安全资源管理器。
全局变量就是定义在函数外的变量,它属于公共资源,在多线程的环境下,访问公共资源就可能会引起冲突,TSRM就是为解决该问题而诞生的。
线程安全机制主要为了保证共享资源的安全。PHP的线程安全机制简洁直观——在多线程环境下,为每个线程提供独立的全局变量副本。具体实施是通过TSRM为每个线程分配(分配前加锁)一个独立ID(自增)作为当前线程的全局变量内存区索引,在以后的全局变量访问中,实现线程之间的完全独立。
PHP大部分SAPI都是单线程的,所以并不需要过多关注线程安全,但是在Apache或者用户自己实现的PHP环境下,就需要考虑线程安全问题了。
二、PHP的设计理念及特点
(1)、多进程模型:由于PHP是多进程模型,不同请求间互不干涉,这样保证了一个请求挂掉不会对全盘服务造成影响,目前PHP也早支持多线程模型。
(2)、弱类型语言:和C/C++、JAVA、C#等语言不同,PHP是一种弱类型的语言。一个变量的类型并不是一开始就确定不变的,运行中才会确定并可能发生隐式或显示的类型转换,这种机制的灵活性在web开发中非常方便、高效,具体会在后面PHP变量中详述。
(3)、引擎(Zend)+组件(ext)的模式降低内部耦合。
(4)、中间层(sapi )Sapi全称是Server Application Programming Interface 隔绝web server和PHP。
(5)、语法简单灵活,没有太多规范。缺点导致风格混杂。
三、PHP核心架构
Zend引擎中包含了编译器和解释器,从PHP代码到opcode的执行,均由Zend引擎完成。
Zend引擎除了实现了PHP的核心功能,还提供了一套接口,让PHP可以在更多的场景中使用,如命令行环境、Web环境等。
该架构图大致分为四大部分。
1、Zend引擎
:前文介绍的词法/语法分析、AST编译和opcodes的执行均在Zend引擎中实现。此外,PHP的变量设计、内存管理、进程管理等也在引擎层实现。引擎为PHP提供了基础服务,PHP的可靠性和高性能都依赖引擎的基础支撑。同时,Zend引擎的可扩展性,还是PHP得以大规模应用的重要原因之一。
2、PHP层
:Zend引擎为PHP提供基础能力(如内存分配和回收),而来自外部的交互则需要通过PHP层来处理。
3、SAPI
:SAPI是Server API的缩写,其中包含了常见的cli SAPI和fpm SAPI。PHP定义好输入/输出规范,依据此规范与PHP交互的一方都可以称为Server。
4、扩展部分
:Zend引擎提供了核心能力和接口规范。在此基础上开发的扩展,为PHP代码的性能和功能的多样性提供了更丰富的选项。
PHP的目录结构、设计理念以及核心架构