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..a52e146 --- /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_opcodes.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) - -## 纸质版 -
-