PHP源码
1. PHP7的新特性
1.太空船操作符 <=>
太空船操作符用于比较两个表达式
例如,当$a
小于、等于或大于$b
时它分别返回-1、0 或 1
2. 类型声明
3. NULL 合并操作符
4. 常量数组
5. NameSpace 批量导入
6. Throwable 接口
7. Closure::call()
8. intdiv 函数
9. list 的方括号写法
10.抽象语法树(AST)
2. 基本变量和内存管理
1.小而巧的 zval
定义:
1 | typedef union _zend_value { |
大小:
类型:
1 | /* regular data types */ |
2.不同变量对应的 zval
例子:
1 |
|
3.zend_string 与写时复制(copy on write)
例子:
1 |
|
4.zend_reference 的使用
例子:
1 |
|
5.PHP7 源码中数组的增删改查
例子:
6.内存管理基础知识
申请和释放内存
malloc
的实现
6.1 PHP 内存接口
6.2 基本概念
chunk
:2MB 大小的内存page
:4KB 大小的内存slot
:一个page
可以划分为多个slot
1chunk = 512page
6.3 内存规格
内存预分配:使用 mmap 分配 chunk
内存分类
a. small
内存(size<=3KB),30 种规格
b. large
内存(3KB<size<=2MB-4KB),是 4KB 的整数倍
c. huge
内存(size>2MB-4KB),是 2MB 的整数倍
6.4 内存分配流程
内存管理emalloc
内存分配过程
6.5 small 内存
6.6 small 内存实战
例子:
注意:
传过来的
size
大小,返回的不一定是size
大小的内存。返回的是能够cover
住size
的最小规格的内存。如申请7B的大小,返回的是8。申请小块内存时,先申请一个
page
,把它切割成相同大小的内存,然后把这些相同大小的内存的第一个返回,剩下的通过单向链表连接起来,挂在free_slot
上,以备后需。根据内存的地址,可以快速的知道内存的大小。
6.7 内存对齐
6.8 全局变量
6.9 内存类型标记
6.10 内存标记和内存释放时大小的判断
例子:
3. PHP运行的生命周期
3.1 CLI 模式的生命周期
3.1.1 模块初始化部分函数调用图
3.1.2 请求初始化阶段
3.1.3 详细执行和管理阶段
3.1.4 请求关闭阶段
3.1.5 模块关闭阶段
3.2 FPM 模式的生命周期
3.2.1 何为 FPM 的三种模式?
pm=static
pm=dynamic
pm=ondemand
注意:Master
进程不提供服务,只是管理 worker
进程,当 worker
进程挂掉之后,会重新拉一个新的 worker
进程提供服务!
3.3 详解 FastCGI 协议
Nginx
收到HTTP
请求,然后Nginx
直接把HTTP
协议的包进行解包然后做一次封装,然后转发给PHP-FPM
,一般PHP-FPM
监听9000
端口,Nginx
向PHP-FPM
发出的请求就是FastCGI
编码的,这里是一个个的键值对,又有头部和尾部的一个编码,然后PHP-FPM
对FastCGI
的协议的一个解码,然后走到FPM
的生命周期里面,然后转到index.php
或者其他PHP
文件里面,然后进行脚本的执行,执行完以后,合成一个FastCGI
协议返送给Nginx
,返回的时候比较简单一些,按照HTTP
协议的方式进行内容编码,但是还是FastCGI
协议,Nginx
再解析成HTTP
协议发送给客户端。
总结:
整个FPM
模式实际上是一个多进程模式,首先由calling process
进程fork
出master
进程,然后master
进程会创建Socket
,然后fork
出worker
进程,worker
进程会在accept
处阻塞等待,请求过来时,由其中一个worker
进程处理,按照FastCGI
模式进行各阶段读取,另外,FPM
建立计分板机制,关注全部和每个worker
工作情况,方便使用者监控。
3.3.1 FastCGI 协议实战
通过抓包工具抓包理解:tcpdump -i lo port 9000 -XX -S
3.4 运行原理
3.4.1 常见的4种PHP运行模式
CGI 模式
CGI
就是将Web
服务器和PHP
执行程序连接起来,把接收的指令传递给PHP
执行程序,每有一个用户请求,都会先要创建CGI
的子进程,然后处理请求,用户请求数量非常多会大量挤占系统的资源,造成效率低下,所以有多少连接请求就有多少CGI
子进程,子进程反复加载是导致CGI
性能低下的主要原因。
Fast-CGI 模式
是CGI
的升级版本,FastCGI
像是一个常驻型的 CGI
,它可以一直执行着,只要激活后,不会每次都要花费时间去fork
一次,也是一种协议。FastCGI
的工作原理是:
Web Server
启动时载入FastCGI
进程管理器【PHP
的FastCGI
进程管理器是PHP-FPM
(php-FastCGI Process Manager
)】(IIS
是ISAPI
、Apache
是Module
);FastCGI
进程管理器自身初始化,启动多个CGI
解释器进程 (在任务管理器中可见多个php-cgi.exe
)并等待来自Web Server
的连接。- 当客户端请求到达
Web Server
时,FastCGI
进程管理器选择并连接到一个CGI
解释器。Web server
将CGI
环境变量和标准输入发送到FastCGI
子进程php-cgi
。 FastCGI
子进程完成处理后将标准输出和错误信息从同一连接返回Web Server
。当FastCGI
子进程关闭连接时,请求便处理完成。FastCGI
子进程接着等待并处理来自FastCGI
进程管理器(运行在Web Server
中)的下一个连接。在正常的CGI
模式中,php-cgi.exe
在此便退出了。
在CGI
模式中,可以想象 CGI
通常有多慢。每一个Web
请求PHP
都必须重新解析php.ini
、重新载入全部dll
扩展并重新初始化全部数据结构。使用FastCGI
,所有这些都只在进程启动时发生一次。
CLI 模式
模块模式
Apache + mod_php
lighttp + spawn-fcgi
nginx + PHP-FPM
(php
在Nginx
中运行模式)
3.4.2 运行原理
PHP-CGI
:cgi
是一种协议,而php-cgi
是实现了这种协议的进程。不过这种实现比较烂。它是单进程的,一个进程处理一个请求,处理结束后进程就销毁。
PHP-FPM
:是对php-cgi
的改进,它直接管理多个php-cgi
进程/线程。也就 是说,php-fpm
是php-cgi
的进程管理器,因此它也算是fast-cgi
协议的实现。
php
的运行原理:就是在服务器启动时,自动载入PHP-FPM
进程管理器,从而管理多个PHP-CGI
进程来准备响应用户的请求,如下图所示:
由于php-cgi
是随服务器启动载入的,所以初始化变量只会发生一次。
3.4.3 SAPI简介
SAPI
相当于PHP
外部环境的代理器。PHP
可以应用在终端上(CLI SAPI
),也可以应用在Web
服务器上(CGI SAPI
)。
4. PHP代码的编译与执行
1.解释型语言也需要编译?
编译型语言
解释型语言
2.词法分析入门
2.1 NFA(不确定有穷自动机)
- 正则表达式 (a|b)*abb
abb/aabb/babb/aababb
a/ab/bb/acabb
2.2 DFA(确定有穷自动机)
2.3 实战:使用 re2c 做词法分析
例子:/home/git/study/php_bottom/chapter5/integer.l
3.语法分析入门
- a = b + c * 2
3.1 巴科斯范式
3.2 实战:使用 bison 做语法分析
例子:/home/git/study/php_bottom/chapter5/calc.y
4.PHP7中词法和语法分析
Zend/zend_language_scanner.l
Zend/zend_language_parser.y
4.1 ast 相关数据结构
_zend_ast
_zend_ast_list
_zend_ast_zval
_zend_ast_decl
4.2 实战:php7 词法分析过程
例子:/home/git/study/php_bottom/chapter5/a.php
4.3 实战:PHP7 语法分析过程
例子:/home/git/study/php_bottom/chapter5/a.php
5. AST的编译
- $a = 1;
5.1 opcode 相关的数据结构
Struct _zend_op
Struct _zend_op_array
Struct _zend_execute_data
Struct _zend_vm_stack
5.2 AST 编译成指令集
6.Zend虚拟机
6.1 基础
6.2 Zend虚拟机的执行
5. 基本语法实现的原理
1.break 语法
1.1 生成的 AST
1.2 栈、符号表和常量
1.3 指令集
1.4 执行过程
实例:/home/git/study/php_bottom/chapter6/break.php
2. include 语法
2.1 生成的 AST
2.2 栈、符号表和常量
2.3 指令集
2.4 执行过程
例子:/home/git/study/php_bottom/chapter6/2.php
生成的 AST
指令集
3.if 语法
3.1 生成的 AST
3.2 栈、符号表和常量
3.3 指令集
3.4 执行过程
例子:/home/git/study/php_bottom/chapter6/condition.php
4.foreach 语法
4.1 生成的 AST
4.2 栈、符号表和常量
4.3 指令集
4.4 执行过程