Skip to content

Commit 7ff4c7f

Browse files
committed
prepare to transfer from sae to vps.
1 parent cc348e5 commit 7ff4c7f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+250
-427
lines changed

1.1.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,3 @@
1212
* 上一节: [PHP的生命周期](<1.md>)
1313
* 下一节: [PHP的启动与终止](<1.2.md>)
1414

15-
## LastModified
16-
* $Id$

1.2.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# 1.2 PHP的启动与终止
22

33
PHP程序的启动可以看作有两个概念上的启动,终止也有两个概念上的终止。其中一个是PHP作为Apache(拿它举例,板砖勿扔)的一个模块的启动与终止,这次启动php会初始化一些必要数据,比如与宿主Apache有关的,<b>并且这些数据是常驻内存的!</b>,终止与之相对。还有一个概念上的启动就是当Apache分配过一个页面请求来的时候,PHP会有一次启动与终止,这也是我们最常讨论的一种。
4+
45
现在我们主要来看一个PHP扩展的生命旅程是怎样走完这四个过程的。
6+
57
在最初的初始化时候,就是PHP随着Apache的启动而诞生在内存里的时,它会把自己所有已加载扩展的MINIT方法(俗称Module Initialization,模块初始化?其实是个函数)都执行一遍。在这个时间里,扩展可以定义一些自己的常量、类、资源等所有会被用户端的PHP脚本用到的东西。但你要记住,这里定义的东东都会随着Apache常驻内存,可以被所有请求使用,直到Apache卸载掉PHP模块!
8+
69
内核中预置了PHP_MINIT_FUNCTION宏函数,来帮助我们实现这个功能:
710
````c
811
//抛弃作者那个例子,书才看两页整那样的例子太复杂了!
@@ -26,6 +29,7 @@ PHP_RINIT_FUNCTION(walu)
2629
2730
````
2831
好了,现在这个页面请求执行的差不多了,可能是顺利的走到了自己文件的最后,也可能是出师未捷,半道被用户给die或者exit了,这时候PHP便会启动回收程序,收拾这个请求留下的烂摊子。它这次会执行所有已加载扩展的RSHUTDOWN(俗称Request Shutdown)方法,这时候扩展可以抓紧利用内核中的变量表啊之类的做一些事情,因为一旦PHP把所有扩展的RSHUTDOWN方法执行完,便会释放掉这次请求使用过的所有东西,包括变量表的所有变量、所有在这次请求中申请的内存等等。
32+
2933
内核预置了PHP_RSHUTDOWN_FUNCTION宏函数来帮助我们实现这个功能
3034
````c
3135
PHP_RSHUTDOWN_FUNCTION(walu)
@@ -38,6 +42,7 @@ PHP_RSHUTDOWN_FUNCTION(walu)
3842

3943
````
4044
前面该启动的也启动了,该结束的也结束了,现在该Apache老人家歇歇的时候,当Apache通知PHP自己要Stop的时候,PHP便进入MSHUTDOWN(俗称Module Shutdown)阶段。这时候PHP便会给所有扩展下最后通喋,如果哪个扩展还有未了的心愿,就放在自己MSHUTDOWN方法里,这可是最后的机会了,一旦PHP把扩展的MSHUTDOWN执行完,便会进入自毁程序,这里一定要把自己擅自申请的内存给释放掉,否则就杯具了。
45+
4146
内核中预置了PHP_MSHUTDOWN_FUNCTION宏函数来帮助我们实现这个功能:
4247
````c
4348
PHP_MSHUTDOWN_FUNCTION(walu)
@@ -49,6 +54,7 @@ PHP_MSHUTDOWN_FUNCTION(walu)
4954
5055
````
5156
这四个宏都是在walu.c里完成最终实现的,而他们的则是在/main/php.h里被定义的(其实也是调用的别的宏,本节最后我把这几个宏给展开了,供有需要的人查看)。
57+
5258
<b>好了,现在我们本节内容说完了,下面我们把所有的代码合在一起,并预测一下应该出现的结果:</b>
5359
````c
5460
//这些代码都在walu.c里面,不再.h里
@@ -107,5 +113,3 @@ PHP_FUNCTION(walu_test)
107113
* 上一节: [让我们从SAPI开始](<1.1.md>)
108114
* 下一节: [PHP的生命周期](<1.3.md>)
109115
110-
## LastModified
111-
* $Id$

1.3.md

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,43 @@
77
<li>多线程模块</li>
88
<li>Embedded(嵌入式,在自己的C程序中调用Zend Engine)</li>
99
</ul>
10+
1011
## 1、CLI/CGI时的周期
12+
1113
CLI和CGI的SAPI是相当特殊的,因为这时PHP的生命周期完全在一个单独的请求中完成。虽然简单,不过我们以前提过的两种init和两种shutdown仍然都会被执行。图1.1展示了PHP在这种模式下是怎么工作的。
12-
<p style="text-align:center"><img src="image/01fig01.jpg" />
14+
15+
<center><img src="image/01fig01.jpg" /></center>
16+
1317
## 2、多进程模式下
1418
<span class="ps">[ps:书是2006年出版的,所以你应该理解作者说多进程是主流]</span>PHP最常见的工作方式便是编译成为Apache2 的Pre-fork MPM或者Apache1 的APXS 模式,其它web服务器也大多用相同的方式工作,在本书后面,把这种方式统一叫做多进程方式。给它起这个名字是有原因的,不是随便拍拍屁股拍拍脑袋定下来的。当Apache启动的时候,会立即把自己fork出好几个子进程,每一个进程都有自己独立的内存空间,也就代表了有自己独立的变量、函数等。在每个进程里的PHP的工作方式如下图所示:
15-
<p style="text-align:center"><img src="image/01fig02.jpg"
19+
20+
<center><img src="image/01fig02.jpg" /></center>
21+
1622
因为是fork出来的,所以各个进程间的数据是无法直接相互影响的,无法读也无法写<span class="ps">(ps:fork后可以用管道等方式实现进程间通信)</span>。它允许每个子进程几乎可以做任何事情,玩七十码、躲猫猫都没人管,办公室拿砍刀玩自杀也没事,但是人家不一样的是人家有个前提:不能影响其它进程的稳定!下图展示了从apache的视角来看多进程工作模式下的PHP:
17-
<p style="text-align:center"><img src="image/01fig03.jpg" />
23+
24+
<center><img src="image/01fig03.jpg" /></center>
25+
1826
## 3、多线程模式下
27+
1928
随着时代的进步,PHP越来越多的在多线程模式下工作,就像IIS的isapi和Apache MPM worker<span class="ps">(支持混合的多线程多进程的多路处理模块)</span>。在这种模式下,只有一个服务器进程在运行着,但会同时运行很多线程,这样可以减少一些资源开销,向Module init和Module shutdown就只需要运行一遍就行了,一些全局变量也只需要初始化一次,因为线程独具的特质,使得各个请求之间方便的共享一些数据成为可能。下图展示了在这种模式下PHP的工作流程:
20-
<p style="text-align:center"><img src="image/01fig04.jpg" />
29+
30+
<center><img src="image/01fig04.jpg" /></center>
31+
2132
## 4、Embed
2233
Embed SAPI是一种比较特殊的sapi,容许你在C/C++语言中调用PHP/ZE提供的函数。并且这种sapi和上面的三种一样,按Module Init、Request Init、Rshutdown、mshutdown的流程执行着。 当然,这只是其中一种情况。因为特定的应用由自己特殊的需求,只是在处理PHP脚本这个环节基本一致。
34+
2335
真正令emebed模式独特的是因为它可能随时嵌入到某个程序里面去(<span class="ps">比如你的test.exe里</span>),然后被当作脚本的一部分在一个请求的时候执行。控制权在PHP和原程序间来回传递。关于嵌入式的PHP在第20章会有应用,到时我们再用实例介绍这个不经常使用的sapi。
2436

25-
<aside>
26-
<hr />
27-
关于Embed SAPI应用的文章
28-
<ul>
29-
<li> [Laruence大哥的使用PHP Embed SAPI实现Opcodes查看器](http://www.laruence.com/2008/09/23/539.html) </li>
30-
</ul>
31-
</aside>
37+
38+
<hr />
39+
## 关于Embed SAPI应用的文章
40+
* [Laruence大哥的使用PHP Embed SAPI实现Opcodes查看器](http://www.laruence.com/2008/09/23/539.html) </li>
41+
42+
3243

3344

3445
## links
46+
* [目录](<preface.md>)
3547
* 上一节 [PHP的启动与终止](<1.2.md>)
3648
* 下一节 [线程安全](<1.4.md>)
3749

38-
## LastModified
39-
* $Id$

1.4.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
# 1.4 PHP的生命周期
22

33
## 这一节没有翻译完,而且应该把这一节挪到后面的某一节里去
4+
45
在PHP初期,是作为单进程的CGI来运行的,所以并没有考虑线程安全问题。我们可以随意的在全局作用域中设置变量并在程序中对他进行修改、访问,内核申请的资源如果没有正确的释放,也会在CGI进程结束后自动地被清理干净。
6+
57
然后,php被作为apache多进程模式下的一个模块运行,但是这仍然把php局限在一个进程里,我们设置的全局变量,只要在每个请求之前将其正确的初始化,并在每个请求之后正确的清理干净,便不会带来什么麻烦。由于对于一个进程来说,同一个时间只能处理一个请求,所以这是内核中加入了针对每个请求的内存管理功能,来防止服务器资源利用出现错误。
68
现在,一个进程多个线程的工作方式被越来越多的采用,所以,php内核中亟需一种新的资源管理方式,其最终在php内核中形成了一个新的抽象层:TSRM(Thread Safe Resource Management)。
9+
710
## 线程安全与非线程安全
11+
812
在一个没有线程的程序中,我们往往倾向于把全局变量声明在源文件的顶部,编辑器会自动的为它分配资源供我们在声明语句之下的程序逻辑中使用。<span class="ps">(即使通过fork()出一个子进程,它也会重新申请一段内存,父子进程中的变量从此没有了任何联系)</span>
13+
914
但是在一个多线程的程序中,如果我们需要每个线程都用有自己独立的资源的话,便需要为每个线程独立开辟出一个区域来存放它们各自的资源,在线程里使用资源的时候,它便会去自己的那一亩三分地里去找,而不会拔了别人的庄稼。
15+
1016
## Thread-Safe Data Pools(线程安全的资源池?)
17+
1118
在扩展的Module Init里,扩展可以调用ts_allocate_id()来告诉TRSM自己需要多少资源,TRSM接收后更新系统使用的资源,并得到一个指向刚分配的那份资源的id。
1219
````c
1320
typedef struct {
@@ -33,5 +40,3 @@ PHP_MINIT_FUNCTION(sample)
3340
* 上一节: [PHP的生命周期](<1.3.md>)
3441
* 下一节: [小结](<1.5.md>)
3542
36-
## LastModified
37-
* $Id$

1.5.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,3 @@
88
* 上一节: [线程安全](<1.4.md>)
99
* 下一节: [PHP变量在内核中的实现](<2.md>)
1010

11-
## LastModified
12-
* $Id$

1.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@
88
* 5. [小结](1.5.html)
99

1010
在平常的Web环境中,我们并不需要单独启动PHP,它一般都会作为一个模块自动加载到web-server里面去,如apache加载的php5.so。只要我们启动了web-server,被一起加载的php便会和服务器一起解析被请求的php脚本。
11+
1112
当然,这不是绝对的,当我们以fastcgi模式安装php的时候,往往就需要手动在终端运行php -b 127.0.0.1:9999来启动php,这个命令只是个例子,可能你的和我的并不一样。没记错的话,我的应该是我在fedora15上配置nginx+php时的一条命令。
1213

1314
## links
1415
* [目录](<preface.md>)
1516
* 下一节: [让我们从SAPI开始](<1.1.md>)
1617

17-
## LastModified
18-
* $Id$

10.1.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,3 @@ $obj = new myclass();
3434
* 10 [PHP中的面向对象(一)](<10.md>)
3535
* 10.2 [定义一个类](<10.2.md>)
3636

37-
## LastModified
38-
* $Id$

10.2.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,5 +199,3 @@ ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char
199199
* 10.1 [zend_class_entry](<10.1.md>)
200200
* 10.3 [定义一个接口](<10.3.md>)
201201

202-
## LastModified
203-
* $Id$

10.3.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,3 @@ $obj->hello();
5252
* 10.2 [定义一个类](<10.2.md>)
5353
* 10.4 [继承与实现接口](<10.4.md>)
5454

55-
## LastModified
56-
* $Id$

10.4.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,3 @@ static zend_function_entry i_myinterface[]=
124124
* 10.3 [定义一个接口](<10.3.md>)
125125
* 10.5 [小结](<10.5.md>)
126126

127-
## LastModified
128-
* $Id$

10.5.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,3 @@
77
* 10.4 [继承与实现接口](<10.4.md>)
88
* 11 [PHP中的面向对象(二)](<11.md>)
99

10-
## LastModified
11-
* $Id$

10.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,3 @@
1414
* 9.4 [第九章小结](<9.4.md>)
1515
* 10.1 [zend_class_entry](<10.1.md>)
1616

17-
## LastModified
18-
* $Id$

11.1.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,3 @@ ZEND_MINIT_FUNCTION(test)
9898
* 11 [PHP中的面向对象(二)](<11.md>)
9999
* 11.2 [读写对象的属性](<11.2.md>)
100100
101-
## LastModified
102-
* $Id$

11.2.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,3 @@ ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, char *
9292
* 11.1 [生成对象的实例](<11.1.md>)
9393
* 11.3 [小结](<11.3.md>)
9494
95-
## LastModified
96-
* $Id$

11.3.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,3 @@
99
* 11.2 [读写对象的属性](<11.2.md>)
1010
* 0 []()
1111

12-
## LastModified
13-
* $Id$

11.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,3 @@ PHP语言中的面向对象其实是分为三个部分来实现的,class、obj
1313
* 10.5 [小结](<10.5.md>)
1414
* 11.1 [生成对象的实例](<11.1.md>)
1515

16-
## LastModified
17-
* $Id$

12.1.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,5 +117,3 @@ EG( persistent_list ) HashTable中的持久性资源,因为他们往往​
117117
* 上一节: [启动与终止的那点事](<12.md>)
118118
* 下一节: [MINFO与phpinfo](<12.2.md>)
119119

120-
## LastModified
121-
* $Id$

12.2.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,3 @@ PHP_MINFO_FUNCTION(sample4) {
8383
* 12.1 [关于生命周期](<12.1.md>)
8484
* 12.3 [常量](<12.1.md>)
8585
86-
## LastModified
87-
* $Id$

12.3.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,3 @@ void php_sample4_register_boolean_constant(char *name, uint len,
8282
* 12.2 [MINFO与phpinfo](<12.2.md>)
8383
* 12.4 [常量](<12.4.md>)
8484
85-
## LastModified
86-
* $Id$

12.4.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,3 @@ FG() | 文件全局变量。大多数文件I/O或相关的全局变量的数据
157157
* 12.3 [常量](<12.3.md>)
158158
* 12.5 [PHP语言中的超级全局变量](<12.5.md>)
159159
160-
## LastModified
161-
* $Id$

12.5.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,3 @@ PHP_RINIT_FUNCTION(sample4) {
8484
* 12.4 [PHP扩展中的全局变量](<12.4.md>)
8585
* 12.6 [小结](<12.6.md>)
8686
87-
## LastModified
88-
* $Id$

12.6.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,3 @@
77
* 12.5 [PHP语言中的超级全局变量](<12.5.md>)
88
* 13.md [设置INI](<13.md>)
99

10-
## LastModified
11-
* $Id$

12.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,3 @@
1818
* 11.3 [小结](<11.3.md>)
1919
* 12.1 [关于生命周期](<12.1.md>)
2020

21-
## LastModified
22-
* $Id$

2.1.md

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# 2.1 第二章目录
22

33
PHP在内核中是通过zval这个结构体来存储变量的,它的定义在Zend/zend.h文件里,简短精炼,只有四个成员组成:
4+
45
````c
56
struct _zval_struct {
67
zvalue_value value; /* 变量的值 */
@@ -15,7 +16,10 @@ typedef unsigned int zend_uint;
1516
typedef unsigned char zend_uchar;
1617

1718
````
19+
1820
zval里的refcout__gc是zend_uint类型,也就是unsinged int型,is_ref__gc和type则是unsigned char型的。<br />保存变量值的value则是zvalue_value类型(PHP5),它是一个Union,同样定义在了Zend/zend.h文件里:
21+
22+
1923
````c
2024
typedef union _zvalue_value {
2125
long lval; /* long value */
@@ -28,7 +32,8 @@ typedef union _zvalue_value {
2832
zend_object_value obj;
2933
} zvalue_value;
3034

31-
````
35+
````
36+
3237
在以上实现的基础上,PHP语言得以实现了8种数据类型,这些数据类型在内核中的分别对应于特定的常量,它们分别是:
3338
<table>
3439
<tr>
@@ -46,11 +51,13 @@ typedef union _zvalue_value {
4651
<tr>
4752
<td>IS_LONG</td>
4853
<td>PHP语言中的整型,在内核中是通过所在操作系统的singed long数据类型来表示的。在最常见的32位操作系统中,它可以存储从-2147483648 到 +2147483647范围内的任一整数。有一点需要注意的是,如果PHP语言中的整型变量超出最大值或者最小值,它并不会直接溢出,而是会被内核转换成IS_DOUBLE类型的值然后再参与计算。再者,因为使用了singed long来作为载体,所以这也就解释了为什么PHP语言中的整型数据都是带符号的了。
49-
<br /><code c>
54+
55+
````c
5056
$a=2147483647;
5157
$a++;
52-
echo $a;//会正确的输出 2147483648;
53-
</code></td>
58+
echo $a;//会正确的输出 2147483648;
59+
````
60+
</td>
5461
</tr>
5562
<tr>
5663
<td>IS_DOUBLE</td>
@@ -74,7 +81,9 @@ echo $a;//会正确的输出 2147483648;
7481
</tr>
7582
</table>
7683
zval结构体里的type成员的值便是以上某个IS_*常量之一。内核通过检测变量的这个成员值来知道他是什么类型的数据并做相应的后续处理。
84+
7785
如果要我们检测一个变量的类型,最直接的办法便是去读取它的type成员的值:
86+
7887
````c
7988
void describe_zval(zval *foo)
8089
{
@@ -87,11 +96,13 @@ void describe_zval(zval *foo)
8796
php_printf("这个变量的数据类型不是NULL,这种数据类型对应的数字是: %d", foo->type);
8897
}
8998
}
90-
9199
````
92-
<p style="color:red">上述做法看起来没有错误,但它是一种被强烈禁止一种做法!
100+
101+
**上述做法看起来没有错误,但它是一种被强烈禁止一种做法!**
102+
93103
PHP内核以后可能会修改变量的实现方式,所以检测type的方法可能在以后就不能用了。为了解决这个兼容问题,zend头文件中定义了大量的宏,供我们检测、操作变量使用,使用这些宏不但让我们的程序更易读,还具有更好的兼容性。这里我们用Z_TYPE_P()宏来改写上面那个程序。
94-
<pre class="code">
104+
105+
````c
95106
void describe_zval(zval *foo)
96107
{
97108
if ( Z_TYPE_P(foo) == IS_NULL )
@@ -103,9 +114,12 @@ void describe_zval(zval *foo)
103114
php_printf("这个变量的数据类型不是NULL,这种数据类型对应的数字是: %d", foo->type);
104115
}
105116
}
106-
</pre>
107-
<div class="tip-common">php_printf()函数是内核对printf()函数的一层封装,我们可以像使用printf()函数那样使用它。</div>
108-
以_P一个p结尾的宏的参数大多是*zval型变量,此外获取变量类型的宏还有两个,分别是Z_TYPE和Z_TYPE_PP,前者的参数是zval型,而后者的参数则是**zval。
117+
````
118+
119+
**php_printf()函数是内核对printf()函数的一层封装,我们可以像使用printf()函数那样使用它。**
120+
121+
以_P一个p结尾的宏的参数大多是*zval型变量,此外获取变量类型的宏还有两个,分别是Z_TYPE和Z_TYPE_PP,前者的参数是zval型,而后者的参数则是**zval。
122+
109123
这样我们便可以猜测一下php内核是如何实现gettype这个函数了,代码如下:
110124
````c
111125
//开始定义php语言中的函数gettype
@@ -168,16 +182,14 @@ PHP_FUNCTION(gettype)
168182

169183
````
170184
以上三个宏的定义在Zend/zend_operators.h里,定义分别是:
171-
<code>
185+
````c
172186
#define Z_TYPE(zval) (zval).type
173187
#define Z_TYPE_P(zval_p) Z_TYPE(*zval_p)
174188
#define Z_TYPE_PP(zval_pp) Z_TYPE(**zval_pp)
175-
</code>
176-
189+
````
177190

178191
## links
179-
* 2 [第二章目录](<2.md>)
180-
* 2.2 [变量的值](<2.2.md>)
192+
* [目录](<preface.md>)
193+
* 2 [第二章目录](<2.md>)
194+
* 2.2 [变量的值](<2.2.md>)
181195

182-
## LastModified
183-
* $Id$

0 commit comments

Comments
 (0)