From e90eadd935460d40f819633377f0be9330d3bdea Mon Sep 17 00:00:00 2001 From: Ceelog Date: Fri, 27 Dec 2019 13:21:34 +0800 Subject: [PATCH 1/2] php start --- .gitignore | 1 + 0/start.md | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 123 +--------------------------------- SUMMARY.md | 2 + 4 files changed, 197 insertions(+), 121 deletions(-) create mode 100644 .gitignore create mode 100644 0/start.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f174344 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +_book diff --git a/0/start.md b/0/start.md new file mode 100644 index 0000000..f1a1135 --- /dev/null +++ b/0/start.md @@ -0,0 +1,192 @@ + +# 一段 PHP 代码执行之旅 + +PHP 是一门动态编译执行的高级语言。 + +从一段代码到获得执行结果,需要经历以下几个过程: + +``` +源码 -> 词法/语法解析 -> AST抽象语法树 -> 编译为 OPCODE -> Zend虚拟机引擎执行 -> 输出 +``` + +以一段简单的 PHP 代码为例: +``` + NOP + 7 1 ASSIGN !0, 1 + 8 2 PRE_INC $3 !0 + 3 ASSIGN !1, $3 + 10 4 INIT_FCALL 'plus' + 5 SEND_VAR !0 + 6 SEND_VAR !1 + 7 DO_UCALL $5 + 8 ECHO $5 + 9 > RETURN 1 +``` + +事实上,所有的 PHP 语句都会被编译为 `OPCODE` ,然后交由 Zend 引擎一条条执行,PHP 7.0.12 版本总共定义了 168 类 `OPCODE`: +``` +Zend/zend_vm_`opcode`s.h + +#define ZEND_NOP 0 +#define ZEND_ADD 1 +#define ZEND_SUB 2 +#define ZEND_MUL 3 +#define ZEND_DIV 4 +#define ZEND_MOD 5 +#define ZEND_SL 6 +#define ZEND_SR 7 +#define ZEND_CONCAT 8 +#define ZEND_BW_OR 9 +#define ZEND_BW_AND 10 +#define ZEND_BW_XOR 11 +#define ZEND_BW_NOT 12 +#define ZEND_BOOL_NOT 13 +#define ZEND_BOOL_XOR 14 +#define ZEND_IS_IDENTICAL 15 +#define ZEND_IS_NOT_IDENTICAL 16 +#define ZEND_IS_EQUAL 17 +#define ZEND_IS_NOT_EQUAL 18 +#define ZEND_IS_SMALLER 19 +#define ZEND_IS_SMALLER_OR_EQUAL 20 +#define ZEND_CAST 21 +#define ZEND_QM_ASSIGN 22 +#define ZEND_ASSIGN_ADD 23 +#define ZEND_ASSIGN_SUB 24 +#define ZEND_ASSIGN_MUL 25 +#define ZEND_ASSIGN_DIV 26 +#define ZEND_ASSIGN_MOD 27 +#define ZEND_ASSIGN_SL 28 +#define ZEND_ASSIGN_SR 29 +#define ZEND_ASSIGN_CONCAT 30 +#define ZEND_ASSIGN_BW_OR 31 +#define ZEND_ASSIGN_BW_AND 32 +#define ZEND_ASSIGN_BW_XOR 33 +#define ZEND_PRE_INC 34 +#define ZEND_PRE_DEC 35 +#define ZEND_POST_INC 36 +#define ZEND_POST_DEC 37 +#define ZEND_ASSIGN 38 +#define ZEND_ASSIGN_REF 39 +#define ZEND_ECHO 40 +... +... +... +``` + +以 `ZEND_ECHO`为例,将交由Zend虚拟机的函数 `ZEND_ECHO_SPEC_TMPVAR_HANDLER` 执行 +``` + +Zend/zend_vm_execute.h #40435 + +static ZEND_`OPCODE`_HANDLER_RET ZEND_FASTCALL ZEND_ECHO_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *z; + + SAVE_OPLINE(); + z = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + + if (Z_TYPE_P(z) == IS_STRING) { + zend_string *str = Z_STR_P(z); + + if (ZSTR_LEN(str) != 0) { + zend_write(ZSTR_VAL(str), ZSTR_LEN(str)); // 将字符输出到控制台 !!! + } + } else { + zend_string *str = _zval_get_string_func(z); + + if (ZSTR_LEN(str) != 0) { + zend_write(ZSTR_VAL(str), ZSTR_LEN(str)); + } else if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(z) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(z, BP_VAR_R); + } + zend_string_release(str); + } + + zval_ptr_dtor_nogc(free_op1); + ZEND_VM_NEXT_`OPCODE`_CHECK_EXCEPTION(); +} +``` + +所以,PHP 引擎本身只是一个 C 语言开发的程序,我们写的 PHP 源代码对引擎来说只是一段输入文本。 + +PHP 引擎在完成词法/语法解析后,将 PHP 源码编译为一条条的 `OPCODE` ,再交由相应的函数完成执行,获得最终输出。 + +以上便是一段 PHP 代码的执行之旅,我们还要关注更多细节: + +- PHP 变量是无类型的,在引擎内部是如何表示和存储的呢? +- 数组、类、对象、函数、命名空间、继承、接口等概念是如何实现的呢? +- 顺序、条件、循环等语言结构是怎么编译为 `OPCODE` 的呢? +- php-fpm 和 cli 模式有什么异同呢? +- ...... + +带着这些问题,让我们开启 PHP 内核剖析之旅吧! diff --git a/README.md b/README.md index 566fac0..3e769a8 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,5 @@ # PHP7内核剖析 -```` -原创内容,转载请注明出处~ -代码版本:php-7.0.12 ```` -## 反馈 -[交流&吐槽](https://github.com/pangudashu/php7-internal/issues/3) [错误反馈](https://github.com/pangudashu/php7-internal/issues/2) - -## 纸质版 -
- -
- -[京东](https://item.jd.com/12267210.html) -[当当](http://product.dangdang.com/25185400.html) - -## 目录: -* 第1章 PHP基本架构 - * 1.1 PHP简介 - * 1.2 PHP7的改进 - * [1.3 FPM](1/fpm.md) - * [1.3.1 概述](1/fpm.md) - * [1.3.2 基本实现](1/fpm.md) - * [1.3.3 FPM的初始化](1/fpm.md) - * [1.3.4 请求处理](1/fpm.md) - * [1.3.5 进程管理](1/fpm.md) - * [1.4 PHP执行的几个阶段](1/base_process.md) -* 第2章 变量 - * [2.1 变量的内部实现](2/zval.md) - * [2.2 数组](2/zend_ht.md) - * [2.3 静态变量](2/static_var.md) - * [2.4 全局变量](2/global_var.md) - * [2.5 常量](2/zend_constant.md) -* 第3章 Zend虚拟机 - * [3.1 PHP代码的编译](3/zend_compile.md) - * [3.1.1 词法解析、语法解析](3/zend_compile_parse.md) - * [3.1.2 抽象语法树编译流程](3/zend_compile_opcode.md) - * [3.2 函数实现](3/function_implement.md) - * [3.2.1 内部函数](3/function_implement.md) - * 3.2.2 用户函数的实现 - * [3.3 Zend引擎执行流程](3/zend_executor.md) - * 3.3.1 基本结构 - * 3.3.2 执行流程 - * 3.3.3 函数的执行流程 - * [3.3.4 全局execute_data和opline](3/zend_global_register.md) - * 3.4 面向对象实现 - * [3.4.1 类](3/zend_class.md) - * [3.4.2 对象](3/zend_object.md) - * [3.4.3 继承](3/zend_extends.md) - * [3.4.4 动态属性](3/zend_prop.md) - * [3.4.5 魔术方法](3/zend_magic_method.md) - * [3.4.6 类的自动加载](3/zend_autoload.md) - * [3.5 运行时缓存](3/zend_runtime_cache.md) - * 3.6 Opcache - * 3.6.1 opcode缓存 - * 3.6.2 opcode优化 - * 3.6.3 JIT -* 第4章 PHP基础语法实现 - * [4.1 类型转换](4/type.md) - * [4.2 选择结构](4/if.md) - * [4.3 循环结构](4/loop.md) - * [4.4 中断及跳转](4/break.md) - * [4.5 include/require](4/include.md) - * [4.6 异常处理](4/exception.md) -* 第5章 内存管理 - * [5.1 Zend内存池](5/zend_alloc.md) - * [5.2 垃圾回收](5/gc.md) -* 第6章 线程安全 - * [6.1 什么是线程安全](6/ts.md) - * [6.2 线程安全资源管理器](6/ts.md) -* 第7章 扩展开发 - * [7.1 概述](7/intro.md) - * [7.2 扩展的实现原理](7/implement.md) - * [7.3 扩展的构成及编译](7/extension_intro.md) - * [7.3.1 扩展的构成](7/extension_intro.md) - * [7.3.2 编译工具](7/extension_intro.md) - * [7.3.3 编写扩展的基本步骤](7/extension_intro.md) - * [7.3.4 config.m4](7/extension_intro.md) - * [7.4 钩子函数](7/hook.md) - * [7.5 运行时配置](7/conf.md) - * [7.5.1 全局变量](7/conf.md) - * [7.5.2 ini配置](7/conf.md) - * [7.6 函数](7/func.md) - * 7.6.1 内部函数注册 - * 7.6.2 函数参数解析 - * 7.6.3 引用传参 - * 7.6.4 函数返回值 - * 7.6.5 函数调用 - * [7.7 zval的操作](7/var.md) - * [7.7.1 新生成各类型zval](7/var.md) - * [7.7.2 获取zval的值及类型](7/var.md) - * [7.7.3 类型转换](7/var.md) - * [7.7.4 引用计数](7/var.md) - * [7.7.5 字符串操作](7/var.md) - * [7.7.6 数组操作](7/var.md) - * [7.8 常量](7/constant.md) - * 7.9 面向对象 - * 7.9.1 内部类注册 - * 7.9.2 定义成员属性 - * 7.9.3 定义成员方法 - * 7.9.4 定义常量 - * 7.9.5 类的实例化 - * 7.10 资源类型 - * 7.11 经典扩展解析 - * 7.8.1 Yaf - * 7.8.2 Redis -* 第8章 命名空间 - * [8.1 概述](8/namespace.md) - * [8.2 命名空间的定义](8/namespace.md) - * [8.2.1 定义语法](8/namespace.md) - * [8.2.2 内部实现](8/namespace.md) - * [8.3 命名空间的使用](8/namespace.md) - * [8.3.1 基本用法](8/namespace.md) - * [8.3.2 use导入](8/namespace.md) - * [8.3.3 动态用法](8/namespace.md) - -## 实现PHP新特性 - * [1、break/continue按标签中断语法实现](try/break.md) - * 2、defer语法 - * 3、协程 - * 3.1 协程的原理 - * 3.2 上下文切换 - +本课程是基于 @pangudashu 原始版本 https://github.com/pangudashu/php7-internal 基础上演绎更新 +```` \ No newline at end of file diff --git a/SUMMARY.md b/SUMMARY.md index d26efd0..96dcde8 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,6 +1,8 @@ # PHP7-internal ## 目录 +* 第0章 + * [0.1 一段 PHP 代码执行之旅](0/start.md) * 第1章 PHP基本架构 * 1.1 PHP简介 From 8c754d4516ae7746c612ca8780317bf7ed47b8fd Mon Sep 17 00:00:00 2001 From: Ceelog Date: Fri, 27 Dec 2019 13:31:57 +0800 Subject: [PATCH 2/2] fix --- 0/start.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/0/start.md b/0/start.md index f1a1135..a52e146 100644 --- a/0/start.md +++ b/0/start.md @@ -93,7 +93,7 @@ line #* E I O op fetch ext return opera 事实上,所有的 PHP 语句都会被编译为 `OPCODE` ,然后交由 Zend 引擎一条条执行,PHP 7.0.12 版本总共定义了 168 类 `OPCODE`: ``` -Zend/zend_vm_`opcode`s.h +Zend/zend_vm_opcodes.h #define ZEND_NOP 0 #define ZEND_ADD 1 @@ -146,7 +146,7 @@ Zend/zend_vm_`opcode`s.h Zend/zend_vm_execute.h #40435 -static ZEND_`OPCODE`_HANDLER_RET ZEND_FASTCALL ZEND_ECHO_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ECHO_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1;