一、PHP7语言执行原理

常用的高级语言有很多种,根据运行的方式不同,大体分为两种:编译型语言和解释型语言。

编译是指在应用源程序执行之前,就将程序源代码“翻译”成汇编语言,然后进一步根据软硬件环境编译成目标文件。一般称完成编译工作的工具为编译器

而解释型语言,在程序运行时才被“翻译”为机器语言。但是执行一次“翻译”一次,所以执行效率较低。解释器的工作就是解释型语言中,负责“翻译”源代码的程序。

对于一段C语言代码,需要经过预编译、编译、汇编和链接,才能成为可执行的二进制文件。

以C语言为代表的编译型语言,代码发生更新都要经过以上步骤。

编译型语言的执行示意:
 
 
对编译型语言与解释型语言的区别的理解,立足于源代码被编译成目标平台CPU指令的时机。对于编译型语言,编译结果已经是针对当前CPU体系的指令;而解释型语言,需要先编译成中间代码,再经由该解释型语言的特定虚拟机,翻译成特定CPU体系的指令被执行。解释型语言是在运行过程中,翻译为目标平台的指令。常说解释型语言“慢”,主要也是慢在这里。
在PHP 7中,源代码首先进行词法分析,将源代码切割为多个字符串单元,分割后的字符串称为Token。而一个一个独立的Token是无法表达完整语义的,需经过语法分析阶段,将Token转换为抽象语法树(简称AST)。之后,抽象语法树被转换为机器指令执行。在PHP中,这些指令称为opcode。
 

第1步:源码通过词法分析得到Token。

第2步:基于语法分析器生成抽象语法树(AST)。

第3步:抽象语法树转换为opcodes(opcode指令集合),PHP解释执行opcodes。

1.Token

Token是PHP代码被切割成的有意义的标识。PHP提供了token_get_all()函数来获取PHP代码被切割后的Token.。

二维数组的每个成员数组的第一个值为Token对应的枚举值。第二个值为Token对应的原始字符串内容。第三个值为代码对应的行号。

可见,Token就是一个个的“词块”,但是单独存在的词块不能表达完整的语义,还需要借助规则进行组织串联。语法分析器就是这个组织者。它会检查语法,匹配Token,对Token进行关联。

2.AST

AST是PHP 7版本新特性。在这之前的版本中,PHP代码的执行过程中是没有生成AST这一步的。

AST的节点分为多种类型,对应着PHP语法。

PHP-Parser工具,它可以用来查看PHP代码生成的AST。

注意 PHP-Parser是PHP 7内核作者之一Nikic编写的将PHP源码生成AST的工具。源码见https://github.com/nikic/PHP-Parser

3.opcodes

opcode只是单条指令,opcodes是opcode的集合形式,是PHP执行过程中的中间代码。opcode生成之后由虚拟机执行。

PHP工程优化措施中有一个比较常见的“开启opcache”,指的就是这里的opcodes的缓存(opcodes cache)。通过省去从源码到opcode的阶段,引擎可以直接执行缓存的opcode,以此

提升性能。

借助vld插件,可以直观地看到一段PHP代码生成的opcode。

opcode是PHP 7定义的一组指令标识,指令对应着相应的handler(处理函数)。当虚拟机调用opcode,会找到opcode背后的处理函数,执行真正的处理。

二、内核架构

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源码目录

sapi目录源码

sapi目录是对输入和输出层的抽象,是PHP提供对外服务的规范。

PHP程序的输入可以是来自于命令行的标准输入,也可以是来自基于cgi/fastcgi协议的网络请求。同理,输出可以写到命令行的标准输出,也可以作为基于cgi/fastcgi协议的网络响应返回给客户端。

命令行模式对应的是二进制程序bin/php;内置模块的模式不需要提供二进制程序,作为普通函数供Apache或任意C/C++程序来调用即可;CGI模式对应的是二进制程序bin/cgi;FastCGI模式对应的是二进制程序sbin/php-fpm。

几种常用的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的命令行交互接口。

Zend目录源码

Zend目录是PHP的核心代码。

1.内存管理模块

2.垃圾回收

3.数组实现

main目录源码

main目录是SAPI层和Zend层的黏合剂。

Zend层实现了PHP脚本的编译和执行,sapi层实现了输入和输出的抽象,main目录则起到了承上启下的作用:承上,解析SAPI的请求,分析要执行的脚本文件和参数;启下,调用Zend引擎之前,完成必要的初始化等工作。

ext目录源码

ext是PHP扩展相关的目录,常用的array、str、pdo等系列函数都在这里定义。

TSRM目录源码

PHP在早期更多的是单个进程、单线程模型运行的,在后期才引入了线程安全机制ZTS(Zend Thread Safety)。

TSRM是Thread Safe Resource Manager的缩写——线程安全资源管理器。

线程安全机制主要为了保证共享资源的安全。PHP的线程安全机制简洁直观——在多线程环境下,为每个线程提供独立的全局变量副本。具体实施是通过TSRM为每个线程分配(分配前加锁)一个独立ID(自增)作为当前线程的全局变量内存区索引,在以后的全局变量访问中,实现线程之间的完全独立。

PHP7 源码整体框架的更多相关文章

  1. zepto源码--整体框架--学习笔记

    为了深入学习javascript,根据别人推荐的方法之一:研究源码. 相对而言,之前的项目中仅仅使用过zepto和jquery,当前阶段,看到好几千行的jquery源码,心生敬畏,望而却步,所以选择相 ...

  2. uboot源码整体框架

    源码解压以后,我们可以看到以下的文件和文件夹:  cpu 与处理器相关的文件.每个子目录中都包括cpu.c和interrupt.c.start.S.u-boot.lds. cpu.c:初始化CPU.设 ...

  3. 搭建LNAMP环境(七)- PHP7源码安装Memcached和Memcache拓展

    上一篇:搭建LNAMP环境(六)- PHP7源码安装MongoDB和MongoDB拓展 一.安装Memcached 1.yum安装libevent事件触发管理器 yum -y install libe ...

  4. 搭建LNAMP环境(六)- PHP7源码安装MongoDB和MongoDB拓展

    上一篇:搭建LNAMP环境(五)- PHP7源码安装Redis和Redis拓展 一.安装MongoDB 1.创建mongodb用户组和用户 groupadd mongodb useradd -r -g ...

  5. 搭建LNAMP环境(五)- PHP7源码安装Redis和Redis拓展

    上一篇:搭建LNAMP环境(四)- 源码安装PHP7 一.安装Redis 1.创建redis用户组和用户 groupadd redis useradd -r -g redis -s /sbin/nol ...

  6. MyEclipse如何配置Struts2源码的框架压缩包

    1.MyEclipse如何配置Struts2源码的框架压缩包 如本机的Struts2框架压缩包路径为:D:\MyEclipseUserLibraries\struts\struts-2.3.15.3- ...

  7. PHP7源码之array_flip函数分析

    以下源码基于 PHP 7.3.8 array array_flip ( array $array ) (PHP 4, PHP 5, PHP 7) array_flip - 交换数组中的键和值 arra ...

  8. 菜鸟nginx源码剖析 框架篇(一) 从main函数看nginx启动流程(转)

    俗话说的好,牵牛要牵牛鼻子 驾车顶牛,处理复杂的东西,只要抓住重点,才能理清脉络,不至于深陷其中,不能自拔.对复杂的nginx而言,main函数就是“牛之鼻”,只要能理清main函数,就一定能理解其中 ...

  9. Android5.1源码Xposed框架编译

    介绍 Xposed框架是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作 . 对于Android5.1系统,官方提供 ...

随机推荐

  1. java 使用poi 导入Excel 数据到数据库

    由于我个人电脑装的Excel是2016版本的,所以这地方我使用了XSSF 方式导入 . 1先手要制定一个Excel 模板 把模板放入javaWeb工程的某一个目录下如图: 2模板建好了后,先实现模板下 ...

  2. 并发编程之第三篇(synchronized)

    并发编程之第三篇(synchronized) 3. 自旋优化 4. 偏向锁 撤销-其它线程使用对象 撤销-调用wait/notify 批量重偏向 批量撤销 5. 锁消除 4.7 wait/notify ...

  3. 2020新春公益赛 writeup

    简单的招聘系统 无需注册账号,admin'or 1#登陆,到blank page页面,在输入key处发现有注入点: /pages-blank.php?key=1%27+union+select+1%2 ...

  4. PAT T1013 Image Segmentation

    krustral算法加并查集,按题给要求维护并查集~ #include<bits/stdc++.h> using namespace std; ; const int inf=1e9; i ...

  5. Django中defer和only区别

    defer('id', 'name'):取出对象,字段除了id和name都有 only('id', 'name'):取出对象, 只有id和name ret=models.Author.objects. ...

  6. 杭电2024 C语言合法标识符

    链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=2024 开始真的对这题是一点头绪都没有,简直了.然后事实证明是我想多了,这题主要是把概念给弄清楚 ...

  7. Spring boot 2.x 中使用redis

    一.添加Maven  依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifac ...

  8. 谈谈spring mvc与struts的区别

    1.Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上Spr ...

  9. MySQL数据库索引:索引介绍和使用原则

    本篇目录: 一.数据页与索引页 二.聚簇索引与非聚簇索引 三.唯一索引 四.索引的创建 五.索引的使用规则 六.数据库索引失效情况 本篇正文: 一.数据页与索引页 数据库的表存储分为数据页存储和索引页 ...

  10. 46 求1+2+3+...+n 静态成员函数和静态变量

    题目描述 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 思路: 1)使用构造函数的方法,需要使用sta ...