1.PHP7 的变化:1.抽象语法树在 php 之前的版本,php 代码在语法解析阶段直接生成了 ZendVM 指令,也就是 zend_language_parser.y 中直接生成 opline 指令,这使得编译器与执行器耦合在一起。编译生成的指令供执行引起使用,该指令是在语法解析时直接生成的,加入要把执行引擎换成其他的,就需要修改语法解析规则;或者如果 php 语法规则变了,但对应的执行指令没有变化,那么也需要修改语法解析规则。php7 中增加了抽象语法树,首先是将 php 代码解析成抽象语法树,然后将抽象语法树编译为 ZendVM 指令。抽象语法树的加入使得 php 的编译器和执行器很好的隔离开,编译器不需要关心指令的生成规则,然后执行器根据自己的规则将抽象语法树编译为对应的指令,执行器同样不需要关心该指令的语法规则是什么样子的。2.Native TLSTSRM_CC,TSRM_DC 这2个宏是用于线程安全的。php 中有很多变量需要在不同函数之间共享,多线程的环境下不能简单的通过全局变量来实现,为了适应多线程的应用环境,php 提供了一个线程安全资源管理器,将全局资源进行了线程隔离,不同的线程之间互不干扰。使用全局资源需要先获得本地线程的资源池,这个过程比较占用时间,因此,php5.x 通过参数传递的方式将本线程的资源池传递给其他函数,避免重复查找。这种实现方式使得几乎所有的函数都需要加上接收资源池的参数,也就是 TSRM_DC 宏所加的参数,然后调用其他函数时再把这个参数传递下去,不仅容易遗漏,而且这种方式极不优雅。php7 中使用了 Native TLS(线程局部安全)来保存线程的资源池,简单的说就是通过 __thread 标识一个全局变量,这样这个全局变量就是线程独享的了,不同线程的修改不会互相影响。3.指定函数参数,返回值类型php7 中可以指定函数参数以及返回值的类型。如 function foo(string $anme) : array { ... }这个函数参数必须为 字符串,返回值必须是数组,否则报error错4.zval 结构的变化php5.x 中的:struct _zval_struct {zvalue_value value; //具体值zend_uint refcount_gc;  //引用计数zend_uchar type; //类型zend_uchar is_ref_gc;  //是否引用}typedef union _zvalue_value {long lval;double dval;struct {char *val;int len;} str;HashTable *ht;zend_object_value obj;zend_ast *ast;} zvalue_value;refcount_gc 它记录变量的引用计数,引用计数是php实现自动回收的基础,也就是记录一个变量有多少个地方在使用的一种机制。php5.x 中引用计数是在 zval 中而不是在具体的 value 中,这样一来,导致变量复制时需要复制两个结构,zval,zvalue_value 始终绑定在一起。php7 中将引用计数转移到了具体的 value 中,这样更合理。因为 zval 只是变量的载体,可以简单的认为是变量名,而 value 才是真正的值,这个改变使得 php 变量之间的复制,传递更加简洁,易懂。除此之外,zval 结构的大小也从24byte 减少到了 16byte,这是 php7 能够降低系统资源占用的一个优化点所在。5.异常处理php5.x 中很多操作会直接抛出 error, php7 中会将许多错误改为了异常抛出,这样一来就可以通过 try catch 捕获到,例如:try {test();} catch (Throwble $e) {echo $e->getMessage();}6.HashTable 的变化HashTable,哈希表,散列表,它是 php 中强大的 array() 类型的内部实现结构,也是内核中使用非常频繁的一个结构,函数符号表,类符号表,常量符号表等都是通过 HashTable 实现的。php7 中HashTable 有非常大的变化,HashTable 大小从 72byte 减小到 56byte,同时数组元素 Bucket 结构从 72byte 减小到 32byte。7.执行器execute_data,opline 采用寄存器变量存储,执行器的调度函数为 execute_ex(),这个函数负责执行 php 代码编译生成的 ZendVM 指令。在执行期间会频繁的用到 execute_data,opline 两个变量,在 php5.x 中,这2个变量是由  execute_ex() 通过参数传递给各指令 handle 的,在 php7 中不再采用传参的方式,而是将 execute_data,opline 通过寄存器来进行存储,避免了传参导致的频繁出入栈操作,同时,寄存器相比内存的访问速度快很多。这个优势使得 php 的性能提升了 5% 左右。8.新的参数解析方式php5.x 通过 zend_parse_parameters() 解析函数的参数,php7 中提供了另外一种方式,同时保留了原来的方式,但新的解析方式速度更快。2.PHP 的构成其中 SAPI 是 php 的应用接口层;main 为 php 的主要代码,主要是输入/输出,web通信,以及 php 框架的初始化操作等,比如 fastcgi协议的解析,扩展的加载,php 配置的解析等工作都是它完成的,它位于 ZendVM 的上一层;Zend 目录是 php 解析器的主要实现,即 ZendVM,它是 php 语言的核心实现,php 代码的解释,执行就是 Zend 完成的;ext 是 php 的扩展目录;TSRM 为线程安全相关的实现。1.SAPIPHP 是一个脚本解析器,提供脚本的解析与执行,它的输入是普通的文本,然后由 php 解析器按照预先定义好的语法规则进行解析执行。我们可以在不同的环境中应用这个解析器,比如命令行下,web 环境中,嵌入其他应用中使用。为此,php 提供了一个 SAPI 层适配不同的应用环境,SAPI 可以认为是 php 的宿主环境。SAPI 也是整个 php 框架的最外层一部分,它主要负责 php 框架的初始化工作。如果 SAPI 是一个独立的应用程序,比如 cli,fpm,那么 main 函数也会定义在 SAPI 中。SAPI的代码位于 PHP 源码的 /sapi 目录下。2.ZendVMZendVM 是一个虚拟的计算机,它介于 php 应用于实际计算机中间,我们编写的 php代码就是被它解释执行的。ZendVM 是 php 语言的核心实现,它主要由2个部分组成:编译器,执行器。其中编译器负责将 php 代码解释为执行器可识别的指令,执行器负责执行编译器解释出指令。ZendVM 的角色相当于 Java 中的 JVM,它们都是抽象出来的虚拟计算机,与C/C++ 这类编译型语言不通,虚拟机上的指令并不是机器指令。虚拟机的一个突出优点是跨平台,只需要按照不通平台编译出对应的解释器就可以实现代码的跨平台执行。3.Extension扩展是 php 内核提供的一套用于扩充 php 功能的一种方式。扩展分为 php 扩展,zend 扩展。php 扩展比较常见,而 zend 扩展主要用于 ZendVM,它可以做到更多事情。我们所熟知的 Opcache 就是 Zend 扩展。3.生命周期php 的整个生命周期被划分为:模块初始化阶段(module startup),请求初始化(request startup),执行脚本阶段(execute script),请求关闭阶段(request shutdown),模块关闭阶段(module shutdown)。根据不同 SAPI 的实现,各个阶段的执行情况会有一些差异。比如,命令行下,每执行一个脚本都会完整的经历这些阶段,而 fastcgi 模式下则在启动的时候执行一次模块初始化,然后各个请求只经历请求初始化,执行请求脚本,请求关闭阶段,在 SAPI 关闭时经历模块关闭阶段。main() => php_module_startup() => php_request_startup() => php_execute_script() => php_request_shutdown() => php_module_shutdown()1.模块初始化阶段这个阶段主要进行 php 框架,zend 引擎的初始化操作。该阶段的入口函数为 php_module_startup(),这个阶段一般只在 SAPI 启动的时候执行一次,对于 fpm 而言,就是在 fpm 的 master 进程启动时执行的。该阶段的几个主要处理如下:1.激活 SAPI : sapi_activate(),初始化请求信息SG(request_info),设置读取 POST 请求的 handler 等,在 module_startup 阶段处理完成后将调用sapi_deactivate()。2.启动 PHP 输出 : php_output_startup()。3.初始化垃圾回收器 : gc_globals_ctor(),分配 zend_gc_globals 内存4.启动 Zend 引擎 : zend_startup(),主要包括如下:1.启动内存池 start_memory_maneger()2.设置一些 util 函数句柄(如 zend_error_cb, zend_printf, zend_write 等)3.设置 Zend 虚拟机编译,执行器的函数句柄 zend_compile_file,zend_execute_ex,以及垃圾回收的函数句柄 gc_collect_cycles4.分配函数符号表(CG(function_table)),类符号表(CG(class_table)),常量符号表(EG(zend_constant))表等,如果是多线程的话,还会分配编译器,执行器的全局变量5.注册 Zend 核心扩展 : zend_startup_builtin_functions(),这个扩展是内核提供的,该过程将注册 Zend 核心扩展提供的函数,比如 strlen,define,等;6.注册 Zend 定义的标准常量 : zend_register_standard_constants(),比如 E_ERROR,E_WARNING,E_ALL7.注释 $GLOBALS 超全局变量的获取 handler8.分配 php.ini 配置的存储符号表:EG(ini_directives)5.注册 PHP 定义的常量 : PHP_VERSION,PHP_ZTS,PHP_SAPI 等6.解析 php.ini : 解析完成后所有的 php.ini 配置信息保存在 configuration_hash 哈希表中7.映射 PHP,Zend 核心的 php.ini 配置:根据解析出的 php.ini,获取对应的配置值,将最终的配置插入到 EG(ini_directive)哈希表8.注册用于获取 $_GET,$_POST,$_COOKIE,$_SERVER,$_ENV,$_REQUEST,$_FILES 变量的 $handler9.注册静态编译的扩展 : php_register_internal_extensions_func()10.注册动态加载的扩展 : php_ini_register_register_extensions(),将 php.ini 中配置的扩展加载到 PHP 中11.回调各扩展定义的 module start 钩子函数,即通过 PHP_MINIT_FUNCTION() 定义的函数12.注册 php.ini 中禁用的函数,类 : disable_functions,disable_classes2.请求初始化阶段该阶段是在请求处理前每一个请求都会经历的一个阶段,对于 fpm 而言,是在 worker 进程 accept 一个请求且读取,解析完请求数据后的一个阶段。该阶段的处理函数为php_request_startup()。主要的处理有以下几个:1.激活输出:php_output_activate()2.激活 Zend 引擎:zend_activate(),主要操作如下所述:1.重置垃圾回收器:gc_reset()2.初始化编译器:init_compiler()3.初始化执行器:init_executor(),将 EG(function_table),EG(class_table)分别指向 CG(function_table),CG(class_table),所以 PHP 的编译,执行期间,EG(function_table)与CG(function_table),EG(class_table)与CG(class_table)是同一个值;另外还会初始化全局符号变量表EG(symbol_table),include过的文件符号表EG(included_files)3.激活SAPI:sapi_activate()4.回调各扩展定义的 request startup 钩子函数:zend_activate_modules()3.执行脚本阶段该阶段包括 PHP 代码的编译,执行两个核心阶段,这也是 Zend 引擎最重要的功能。在编译阶段,PHP 脚本将经历从 PHP 源代码到抽象语法树再到 opline 指令的转化过程,最终生成的 opline 指令就是 Zend 引擎可识别的执行指令,这些指令接着被执行器执行,这就是 PHP 代码解释执行的过程。入口函数为 php_execute_script()。4.请求关闭阶段在 PHP 脚本解释执行完成后将进入请求关闭阶段,这个阶段将 flush 输出内容,发送 http 应答头,清理全局变量,关闭编译器,关闭执行器等。另外,在该阶段将回调各个扩展的 request shutdown 钩子函数。该阶段是与请求初始化阶段的相反操作,与请求初始化时的处理一一对应。5.模块关闭阶段该阶段在 SAPI 关闭时执行,与模块初始化阶段对应,这个阶段主要进行资源的清理,PHP 各个模块的关闭操作,同时,将回调各扩展的 module shutdown 钩子函数。具体处理的函数为 php_module_shutdown()。

1.PHP7内核剖析 --- PHP 基础架构相关推荐

  1. (PHP7内核剖析-3) 变量

    1.变量结构 typedef struct _zval_struct zval;typedef union _zend_value {zend_long lval; //int整形double dva ...

  2. OceanBase 从0到1数据库内核实战教程学习笔记 - 3.OceanBase基础架构和开发技巧

    这篇文章主要介绍王泽林老师分享的 <OceanBase 的基础架构和开发技巧>.如果您看过第一篇文章的对应视频,会发现整个系列主要分为 MiniOB 和 OceanBase 两个系列,本篇 ...

  3. MLIR: 编译器基础架构重定义

    MLIR: 编译器基础架构重定义 MLIR(多级中间表示)是语言(如 C)或库(如 TensorFlow)与编译器后端(如 LLVM)之间的中间表示 (IR) 系统.允许不同语言的不同编译器堆栈之间的 ...

  4. Android内核剖析

    -- Android内核剖析  柯元旦 编著 ISBN 978-7-121-14398-4   2011年9月出版 定价:79.90元 16开 616页 内容简介: 本书内容分别从基础.内核.系统.编 ...

  5. 《深入理解Android 5 源代码》——第1章,第1.2节剖析Android系统架构

    本节书摘来自异步社区<深入理解Android 5 源代码>一书中的第1章,第1.2节剖析Android系统架构,作者 李骏,更多章节内容可以访问云栖社区"异步社区"公众 ...

  6. 《Linux内核剖析》(Yanlz+VR云游戏+Unity+SteamVR+云技术+5G+AI+Makefile+块设备驱动+字符设备驱动+数学协处理器+文件系统+内存管理+GDB+立钻哥哥+==)

    <Linux内核剖析> <Linux内核剖析> 版本 作者 参与者 完成日期 备注 YanlzLinux_Kernel0.12_V01_1.0 严立钻 2020.02.06 # ...

  7. 索骥馆-编程语言之《Android内核剖析》扫描版[PDF]

    内容介绍: <android内核剖析>详细分析了android内核的内部机制,包括窗口管理系统.activity管理系统.输入法框架.编译系统等,为android内核定制及高级应用程序开发 ...

  8. LLVM编译器基础架构与DragonEgg示例

    LLVM编译器基础架构与DragonEgg示例 LLVM 概述 LLVM 项目是模块化和可重用的编译器和工具链技术的集合.LLVM 与传统的虚拟机几乎没有关系."LLVM"这个名字 ...

  9. 【Linux开发】linux设备驱动归纳总结(一):内核的相关基础概念

    linux设备驱动归纳总结(一):内核的相关基础概念 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  10. 使用Nomad构建弹性基础架构:重新启动任务

    Nomad是一个功能强大.灵活的调度器,适用于长期运行的服务和批处理任务.通过广泛的驱动程序,Nomad可以调度基于容器的工作负载.原始二进制文件.java应用程序等等.Nomad操作简单,易伸缩,与 ...

最新文章

  1. Linux下Nginx的安装
  2. CF #737(div2) Ezzat and Two Subsequences 找规律
  3. Netty3之ServerBootstrap分析
  4. 计算机网络之网络层:11、移动IP
  5. Linux服务器,服务管理--systemctl命令详解,设置开机自启动
  6. java实现家庭关系图_基于jsp的家族关系管理系统-JavaEE实现家族关系管理系统 - java项目源码...
  7. CSS(十六)——美化表单实操
  8. 从Intel 80386讲讲操作系统的内存管理机制
  9. 中国移动DNS IP地址大全(32个省)
  10. PS 导入笔刷和导入字体和导入滤镜
  11. window终端光标消失
  12. Python3 面向对象编程进阶
  13. 2.4 线性丢番图方程
  14. BP神经网络之鸢尾花
  15. LIO-SAM中的mapOptmization
  16. 【markdown】【xSliders | slidev | mindshow】markdown文档生成PPT/视频
  17. gstreamer(三) 常用命令集锦
  18. 光纤收发器的选择与维护!
  19. C语言编程计算差商表,计算方法C语言编程计算方法C语言编程.doc
  20. 什么是网站权重?网站权重查询方法有哪些?

热门文章

  1. 分组在re模块中的使用
  2. mongodb 的安装使用步骤
  3. python thrift 示例
  4. 爱情六十六课,自我救赎
  5. 【LeetCode】524-通过删除字母匹配到字典里最长单词
  6. 在centos上安装mysql
  7. WebGL 绘制Line的bug(三)
  8. NOIP模拟题——tractor
  9. 20145201 《Java程序设计》第六周学习总结
  10. ffmpeg 转换VC工具已经可以生成工程文件