Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
793759b
Update zval.md
magnetoeric Jun 2, 2017
b5aa507
Merge pull request #9 from magnetoeric/patch-1
pangudashu Jun 2, 2017
1a6ef79
update
imaben Jun 2, 2017
7ea4b9c
Update include.md
iam2c Jun 2, 2017
c9554e3
Update zend_ht.md
magnetoeric Jun 2, 2017
ee5cbe3
Merge pull request #10 from imaben/master
pangudashu Jun 2, 2017
9ec3973
Merge pull request #11 from iam2c/patch-1
pangudashu Jun 2, 2017
7b6d44c
Update zend_ht.md
pangudashu Jun 3, 2017
98a47a4
Merge pull request #12 from magnetoeric/patch-2
pangudashu Jun 3, 2017
e542a3d
fpm实现解析
pangudashu Jun 3, 2017
fb0787a
Merge branch 'master' of github.com:pangudashu/php7-internal
pangudashu Jun 3, 2017
5dc1e91
更新目录
pangudashu Jun 3, 2017
c92ad39
Update fpm.md
iam2c Jun 3, 2017
1b50080
Merge pull request #13 from iam2c/patch-2
pangudashu Jun 3, 2017
11d633b
add weixin
pangudashu Jun 7, 2017
cc7742e
Merge branch 'master' of github.com:pangudashu/php7-internal
pangudashu Jun 7, 2017
dcfacae
add img
pangudashu Jun 7, 2017
7039ba1
修改break实现
pangudashu Jun 9, 2017
7c34ab1
update
pangudashu Jun 9, 2017
215ab14
update
pangudashu Jun 9, 2017
72b5159
update
pangudashu Jun 9, 2017
f167bb6
update
pangudashu Jun 9, 2017
fc4943d
add class register
pangudashu Jun 12, 2017
b2bb49b
更新变量、引用计数操作
pangudashu Jun 13, 2017
75fad3f
命名空间的定义
pangudashu Jun 13, 2017
4e454cc
Create zval.md
zimuyang Jun 13, 2017
ee6b85b
Merge pull request #17 from zimuyang/patch-1
pangudashu Jun 13, 2017
31f60c1
add namespace
pangudashu Jun 14, 2017
325e0ef
Merge branch 'master' of github.com:pangudashu/php7-internal
pangudashu Jun 14, 2017
63ddbbe
finish namespace
pangudashu Jun 14, 2017
336032b
update
pangudashu Jun 14, 2017
c97fe96
Update zend_compile_opcode.md
zimuyang Jun 15, 2017
83bd270
Update function_implement.md
zimuyang Jun 16, 2017
366c812
Merge pull request #18 from zimuyang/master
pangudashu Jun 16, 2017
8db476b
Update zend_executor.md
zimuyang Jun 16, 2017
fdaf1f8
Update zend_object.md
zimuyang Jun 17, 2017
e4b4e27
Merge pull request #20 from zimuyang/master
pangudashu Jun 19, 2017
fda9bae
update zendmm
pangudashu Jun 22, 2017
b3a582d
Merge branch 'master' of github.com:pangudashu/php7-internal
pangudashu Jun 22, 2017
50d5eab
fix error
pangudashu Jun 22, 2017
1719146
update
pangudashu Jun 27, 2017
561a23b
fix error
pangudashu Jun 29, 2017
59056df
fix error
pangudashu Jul 6, 2017
70108cd
fix error
pangudashu Jul 7, 2017
c6983b6
add defer
pangudashu Jul 7, 2017
1a059c2
update
pangudashu Jul 7, 2017
8552cec
add ast
pangudashu Jul 7, 2017
e09183e
update
pangudashu Jul 7, 2017
5acabed
add defer
pangudashu Jul 7, 2017
a5b413b
finish defer
pangudashu Jul 8, 2017
8418b46
finish defer
pangudashu Jul 8, 2017
06499a6
change dir
pangudashu Jul 14, 2017
9a4d814
修复错字
huqinlou0123 Jul 14, 2017
6e5b9f4
update
pangudashu Jul 17, 2017
db02aaf
fix error
pangudashu Jul 17, 2017
95ec461
fix error
pangudashu Jul 17, 2017
56163b4
add global register variables
pangudashu Jul 19, 2017
67ea352
update
pangudashu Jul 19, 2017
34a9e6f
update
pangudashu Jul 19, 2017
ddfbddd
update
pangudashu Jul 19, 2017
8b3d976
update
pangudashu Jul 19, 2017
ac29cb0
update dir
pangudashu Jul 19, 2017
ac38e21
update
pangudashu Jul 19, 2017
5461ded
update
pangudashu Jul 19, 2017
c0de5f8
update
pangudashu Jul 19, 2017
ed96756
update
pangudashu Jul 20, 2017
ee2e98f
Update func.md
huqinlou0123 Jul 21, 2017
06a09de
Merge pull request #22 from huqinlou0123/master
pangudashu Jul 24, 2017
3e09906
fix error
pangudashu Jul 24, 2017
bfdd8fd
update
pangudashu Jul 25, 2017
51236a4
Merge branch 'master' of github.com:pangudashu/php7-internal
pangudashu Jul 25, 2017
163db8b
fix error
pangudashu Jul 25, 2017
337ab9c
update
pangudashu Jul 25, 2017
cec1807
update
pangudashu Jul 26, 2017
a6eec9f
fix error
pangudashu Jul 27, 2017
fb2385c
fix error
pangudashu Jul 27, 2017
3edb26d
fix error
pangudashu Jul 28, 2017
c84843b
fix error
pangudashu Aug 1, 2017
c927500
fix error
pangudashu Aug 4, 2017
42c82f6
fix error
pangudashu Aug 4, 2017
eb2f96f
fix error
pangudashu Aug 7, 2017
b7dbd3d
拼写可能错了
jianzhiyao Aug 29, 2017
e4f5b31
Merge pull request #23 from jianzhiyao/patch-2
pangudashu Aug 30, 2017
386016c
update
pangudashu Nov 13, 2017
1bec029
Merge branch 'master' of github.com:pangudashu/php7-internal
pangudashu Nov 13, 2017
f4c4a40
update
pangudashu Nov 13, 2017
d5ec26a
add gitbook support
Nov 15, 2017
3c0ba79
edit description
Nov 15, 2017
14b1e2a
Merge pull request #25 from glowdan/master
pangudashu Nov 16, 2017
bf67ee7
update
pangudashu Dec 1, 2017
e18db90
Merge branch 'master' of github.com:pangudashu/php7-internal
pangudashu Dec 1, 2017
f89a9ab
add url
pangudashu Dec 1, 2017
254c7b8
add url
pangudashu Dec 1, 2017
9e273d4
add url
pangudashu Dec 1, 2017
6c469f1
add url
pangudashu Dec 1, 2017
6c34d2e
fix 词语错误
Mar 19, 2018
4f585e0
Merge pull request #28 from smalleyes/fixed_word_error
pangudashu Mar 22, 2018
6650554
修复
toxmc Mar 26, 2018
217ea91
校对
toxmc Apr 25, 2018
40645cf
Merge pull request #31 from smalleyes/master
pangudashu Apr 27, 2018
124d6bc
update doc
pangudashu Jul 10, 2018
dfae738
Merge pull request #1 from pangudashu/master
PeakLee Nov 26, 2018
e632cbb
Merge pull request #34 from PeakLee/master
pangudashu Dec 11, 2018
860410b
fix example typo
tomjpsun Jan 18, 2019
2a5f36f
Merge pull request #36 from tomjpsun/master
pangudashu Jun 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
354 changes: 354 additions & 0 deletions 1/fpm.md

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions 2/global_var.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
## 2.4 全局变量
PHP中在函数、类之外直接定义的变量可以在函数、类成员方法中通过global关键词引入使用,这些变量称为:全局变量。

这些直接在PHP中定义的变量(包括include、require文件中的)相对于函数、类方法而言它们是全局变量,但是对自身执行域zend_execute_data而言它们是普通的局部变量,自身执行时它们与普通变量的读写方式完全相同。
PHP中把定义在函数、类之外的变量称之为全局变量,也就是定义在主脚本中的变量,这些变量可以在函数、成员方法中通过global关键字引入使用。

```php
function test() {
Expand Down Expand Up @@ -64,7 +62,7 @@ global $id; // 相当于:$id = & EG(symbol_table)["id"];
![](../img/zend_global_ref.png)

### 2.4.3 超全局变量
全部变量除了通过global引入外还有一类特殊的类型,它们不需要使用global引入而可以直接使用,这些全局变量称为:超全局变量。
全局变量除了通过global引入外还有一类特殊的类型,它们不需要使用global引入而可以直接使用,这些全局变量称为:超全局变量。

超全局变量实际是PHP内核定义的一些全局变量:$GLOBALS、$_SERVER、$_REQUEST、$_POST、$_GET、$_FILES、$_ENV、$_COOKIE、$_SESSION、argv、argc。

Expand Down
2 changes: 1 addition & 1 deletion 2/static_var.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ if (by_ref) {
* __ZEND_FETCH_W:__ 这条opcode对应的操作是创建一个IS_INDIRECT类型的zval,指向static_variables中对应静态变量的zval
* __ZEND_ASSIGN_REF:__ 它的操作是引用赋值,即将一个引用赋值给CV变量

通过上面两条opcode可以确定静态变量的读写过程:首先根据变量名在static_variables中取出对应的zval,然后将它修改为引用类型并赋值给局部变量,也就是说`static $count = 4;`包含了两个操作,严格的将`$count`并不是真正的静态变量,它只是一个指向静态变量的局部变量,执行时实际操作是:`$count = & static_variables["count"];`。上面例子$count与static_variables["count"]间的关系如图所示。
通过上面两条opcode可以确定静态变量的读写过程:首先根据变量名在static_variables中取出对应的zval,然后将它修改为引用类型并赋值给局部变量,也就是说`static $count = 4;`包含了两个操作,严格的说`$count`并不是真正的静态变量,它只是一个指向静态变量的局部变量,执行时实际操作是:`$count = & static_variables["count"];`。上面例子$count与static_variables["count"]间的关系如图所示。

![](../img/zend_static_ref.png)

2 changes: 1 addition & 1 deletion 2/zend_constant.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ PHP中的常量通过`define()`函数定义:
define('CONST_VAR_1', 1234);
```
### 2.5.1 常量的存储
在内核中常量存储在`EG(zend_constant)`哈希表中,访问时也是根据常量名直接到哈希表中查找,其实现比较简单。
在内核中常量存储在`EG(zend_constants)`哈希表中,访问时也是根据常量名直接到哈希表中查找,其实现比较简单。

常量的数据结构:
```c
Expand Down
6 changes: 4 additions & 2 deletions 2/zend_ht.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct _zend_array {
dtor_func_t pDestructor;
};
```
HashTable中有两个非常相近的值:`nNumUsed`、`nNumOfElements`,`nNumOfElements`表示哈希表已有元素数,那这个值不跟`nNumUsed`一样吗?为什么要定义两个呢?实际上它们有不同的含义,当将一个元素从哈希表删除时并不会将对应的Bucket移除,而是将Bucket存储的zval标示为`IS_UNDEF`,只有扩容时发现nNumOfElements与nNumUsed相差达到一定数量(这个数量是:`ht->nNumUsed - ht->nNumOfElements > (ht->nNumOfElements >> 5)`)时才会将已删除的元素全部移除,重新构建哈希表。所以`nNumUsed`>=`nNumOfElements`。
HashTable中有两个非常相近的值:`nNumUsed`、`nNumOfElements`,`nNumOfElements`表示哈希表已有元素数,那这个值不跟`nNumUsed`一样吗?为什么要定义两个呢?实际上它们有不同的含义,当将一个元素从哈希表删除时并不会将对应的Bucket移除,而是将Bucket存储的zval修改为`IS_UNDEF`,只有扩容时发现nNumOfElements与nNumUsed相差达到一定数量(这个数量是:`ht->nNumUsed - ht->nNumOfElements > (ht->nNumOfElements >> 5)`)时才会将已删除的元素全部移除,重新构建哈希表。所以`nNumUsed`>=`nNumOfElements`。

HashTable中另外一个非常重要的值`arData`,这个值指向存储元素数组的第一个Bucket,插入元素时按顺序 __依次插入__ 数组,比如第一个元素在arData[0]、第二个在arData[1]...arData[nNumUsed]。PHP数组的有序性正是通过`arData`保证的,这是第一个与普通散列表实现不同的地方。

Expand All @@ -61,6 +61,8 @@ unset($arr["c"]);

![](../img/zend_hash_1.png)

> 图中Bucket的zval.u2.next默认值应该为-1,不是0

### 2.2.2 映射函数
映射函数(即:散列函数)是散列表的关键部分,它将key与value建立映射关系,一般映射函数可以根据key的哈希值与Bucket数组大小取模得到,即`key->h % ht->nTableSize`,但是PHP却不是这么做的:
```c
Expand Down Expand Up @@ -155,7 +157,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
```

### 2.2.6 重建散列表
当删除元素达到一定数量或扩容后都需要重建散列表,因为value在Bucket位置移动了或哈希数组nTableSize变化了导致key与value的映射关系改变,重建过程实际就是遍历Bucket数组中的value,然后重新计算映射值更新到散列表,除了更新散列表之外,这里还有一个重要的处理:移除已删除的value,开始的时候我们说过,删除value时只是将value的type表为了IS_UNDEF,并没有实际从Bucket数组中删除,如果这些value一直存在那么将浪费很多空间,所以这里会把它们移除,操作的方式也比较简单:将后面未删除的value依次前移,具体过程如下:
当删除元素达到一定数量或扩容后都需要重建散列表,因为value在Bucket位置移动了或哈希数组nTableSize变化了导致key与value的映射关系改变,重建过程实际就是遍历Bucket数组中的value,然后重新计算映射值更新到散列表,除了更新散列表之外,这里还有一个重要的处理:移除已删除的value,开始的时候我们说过,删除value时只是将value的type设置为IS_UNDEF,并没有实际从Bucket数组中删除,如果这些value一直存在那么将浪费很多空间,所以这里会把它们移除,操作的方式也比较简单:将后面未删除的value依次前移,具体过程如下:
```c
//zend_hash.c
ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
Expand Down
8 changes: 4 additions & 4 deletions 2/zval.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ $b = 1;

### 2.1.1 变量的基础结构
```c
//zend_type.h
//zend_types.h
typedef struct _zval_struct zval;

typedef union _zend_value {
Expand Down Expand Up @@ -60,7 +60,7 @@ struct _zval_struct {
};
```
`zval`结构比较简单,内嵌一个union类型的`zend_value`保存具体变量类型的值或指针,`zval`中还有两个union:`u1`、`u2`:
* __u1:__ 它的意义比较直观,变量的类型就通过`u1.type`区分,另外一个值`type_flags`为类型掩码,在变量的内存管理、gc机制中会用到,第三部分会详细分析,至于后面两个`const_flags`、`reserved`暂且不管
* __u1:__ 它的意义比较直观,变量的类型就通过`u1.v.type`区分,另外一个值`type_flags`为类型掩码,在变量的内存管理、gc机制中会用到,第三部分会详细分析,至于后面两个`const_flags`、`reserved`暂且不管
* __u2:__ 这个值纯粹是个辅助值,假如`zval`只有:`value`、`u1`两个值,整个zval的大小也会对齐到16byte,既然不管有没有u2大小都是16byte,把多余的4byte拿出来用于一些特殊用途还是很划算的,比如next在哈希表解决哈希冲突时会用到,还有fe_pos在foreach会用到......

从`zend_value`可以看出,除`long`、`double`类型直接存储值外,其它类型都为指针,指向各自的结构。
Expand Down Expand Up @@ -259,7 +259,7 @@ $a,$b -> zend_string_1(refcount=0,val="hi~")
|reference | Y |
```
simple types很显然用不到,不再解释,string、array、object、resource、reference有引用计数机制也很容易理解,下面具体解释下另外两个特殊的类型:
* __interned string:__ 内部字符串,这是种什么类型?我们在PHP中写的所有字符都可以认为是这种类型,比如function name、class name、variable name、静态字符串等等,我们这样定义:`$a = "hi~;"`后面的字符串内容是唯一不变的,这些字符串等同于C语言中定义在静态变量区的字符串:`char *a = "hi~";`,这些字符串的生命周期为request期间,request完成后会统一销毁释放,自然也就无需在运行期间通过引用计数管理内存。
* __interned string:__ 内部字符串,这是种什么类型?我们在PHP中写的所有字符都可以认为是这种类型,比如function name、class name、variable name、静态字符串等等,我们这样定义:`$a = "hi~";`后面的字符串内容是唯一不变的,这些字符串等同于C语言中定义在静态变量区的字符串:`char *a = "hi~";`,这些字符串的生命周期为request期间,request完成后会统一销毁释放,自然也就无需在运行期间通过引用计数管理内存。

* __immutable array:__ 只有在用opcache的时候才会用到这种类型,不清楚具体实现,暂时忽略。

Expand All @@ -278,7 +278,7 @@ $b[] = 3;

![zval_sep](../img/zval_sep.png)

不是所有类型都可以copy的,比如对象、资源,实时上只有string、array两种支持,与引用计数相同,也是通过`zval.u1.type_flag`标识value是否可复制的:
不是所有类型都可以copy的,比如对象、资源,事实上只有string、array两种支持,与引用计数相同,也是通过`zval.u1.type_flag`标识value是否可复制的:
```c
#define IS_TYPE_COPYABLE (1<<4)
```
Expand Down
4 changes: 2 additions & 2 deletions 3/function_implement.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function my_func(){
...
}
```
汇编中函数对应的是一组独立的汇编指令,然后通过call指令实现函数的调用前面已经说过PHP编译的结果是opcode数组,与汇编指令对应PHP用户自定义函数的实现就是将函数编译为独立的opcode数组,调用时分配独立的执行栈依次执行opcode,所以自定义函数对于zend而言并没有什么特别之处,只是将opcode进行了打包封装,实际PHP脚本中函数之外的指令整个可以认为是一个函数(或者理解为main函数更直观)。
汇编中函数对应的是一组独立的汇编指令,然后通过call指令实现函数的调用前面已经说过PHP编译的结果是opcode数组,与汇编指令对应PHP用户自定义函数的实现就是将函数编译为独立的opcode数组,调用时分配独立的执行栈依次执行opcode,所以自定义函数对于zend而言并没有什么特别之处,只是将opcode进行了打包封装。PHP脚本中函数之外的指令,整个可以认为是一个函数(或者理解为main函数更直观)。

```php
/* function main(){ */
Expand Down Expand Up @@ -287,7 +287,7 @@ $greet = function($name)
$greet('World');
$greet('PHP');
```
这里提函数函数只是想说明编译函数时那个use的用法:
这里提匿名函数只是想说明编译函数时那个use的用法:

__匿名函数可以从父作用域中继承变量。 任何此类变量都应该用 use 语言结构传递进去。__

Expand Down
5 changes: 2 additions & 3 deletions 3/zend_class.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
### 3.4.1 类
类是现实世界或思维世界中的实体在计算机中的反映,它将某些具有关联关系的数据以及这些数据上的操作封装在一起。在面向对象中类是对象的抽象,对象是类的具体实例。

在PHP中类编译阶段的产物,而对象是运行时产生的,它们归属于不同阶段。
在PHP中类是编译阶段的产物,而对象是运行时产生的,它们归属于不同阶段。

PHP中我们这样定义一个类:
```php
Expand Down Expand Up @@ -416,7 +416,7 @@ void zend_compile_class_const_decl(zend_ast *ast)
zend_class_entry *ce = CG(active_class_entry);
uint32_t i;

for (i = 0; i < list->children; ++i) { //不清楚这个地方为什么要用list,试了几个例子这个节点都只有一个child,即for只循环一次
for (i = 0; i < list->children; ++i) { //const声明了多个常量,遍历编译每个子节点
zend_ast *const_ast = list->child[i];
zend_ast *name_ast = const_ast->child[0]; //常量名节点
zend_ast *value_ast = const_ast->child[1];//常量值节点
Expand Down Expand Up @@ -446,7 +446,6 @@ void zend_compile_prop_decl(zend_ast *ast)
zend_class_entry *ce = CG(active_class_entry);
uint32_t i, children = list->children;

//也不清楚这里为啥用循环,测试的情况child只有一个
for (i = 0; i < children; ++i) {
zend_ast *prop_ast = list->child[i]; //这个节点类型为:ZEND_AST_PROP_ELEM
zend_ast *name_ast = prop_ast->child[0]; //属性名节点
Expand Down
10 changes: 5 additions & 5 deletions 3/zend_compile_opcode.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ int main()
return 0;
}
```
我们知道name的值分配在栈上,而"pangudashu"分配在常量区,那么"name"变量名分配在哪呢?
我们知道指针name分配在栈上,而"pangudashu"分配在常量区,那么"name"变量名分配在哪呢?

实际上C里面是不会存变量名称的,编译的过程会将变量名替换为偏移量表示:`ebp - 偏移量`或`esp + 偏移量`,将上面的代码转为汇编:
```c
Expand All @@ -272,7 +272,7 @@ main:

![php vs c](../img/php_vs_c.png)

在编译时就可确定且不会改变的量称为字面量,也称作常量(IS_CONST),这些值在编译阶段就已经分配zval,保存在`zend_op_array->literals`数组中(对应c程序的常量内存区),访问时通过`_zend_op_array->literals + 偏移量`读取,举个例子:
在编译时就可确定且不会改变的量称为字面量,也称作常量(IS_CONST),这些值在编译阶段就已经分配zval,保存在`zend_op_array->literals`数组中(对应c程序的常量存储区),访问时通过`_zend_op_array->literals + 偏移量`读取,举个例子:
```c
<?php
$a = 56;
Expand Down Expand Up @@ -372,11 +372,11 @@ void zend_compile_stmt(zend_ast *ast)
switch (ast->kind) {
case xxx:
...
break;
break;
case ZEND_AST_ECHO:
zend_compile_echo(ast);
break;
...
...
default:
{
znode result;
Expand Down Expand Up @@ -516,7 +516,7 @@ void zend_compile_expr(znode *result, zend_ast *ast)
```
>> __第3步:__ 上面两步已经分别生成了变量赋值的op1、op2,下面就是根据这俩值生成opcode的过程。
```c
tatic zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2)
static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2)
{
zend_op *opline = get_next_op(CG(active_op_array)); //当前zend_op_array下生成一条新的指令
opline->opcode = opcode;
Expand Down
2 changes: 1 addition & 1 deletion 3/zend_executor.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ ZEND_API zend_executor_globals executor_globals;
struct _zend_execute_data {
const zend_op *opline; //指向当前执行的opcode,初始时指向zend_op_array起始位置
zend_execute_data *call; /* current call */
zval *return_value; //返回值指针 */
zval *return_value; //返回值指针
zend_function *func; //当前执行的函数(非函数调用时为空)
zval This; //这个值并不仅仅是面向对象的this,还有另外两个值也通过这个记录:call_info + num_args,分别存在zval.u1.reserved、zval.u2.num_args
zend_class_entry *called_scope; //当前call的类
Expand Down
Loading