Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/wenjun1055/phpbook
Browse files Browse the repository at this point in the history
Conflicts:
	1.2.md
	1.3.md
	1.4.md
	2.1.md
	2.3.md
	2.md
	3.1.md

merge with walu and complete chapter three
  • Loading branch information
[email protected] committed Dec 23, 2012
2 parents 772bd29 + 7826efe commit aa17971
Show file tree
Hide file tree
Showing 68 changed files with 360 additions and 518 deletions.
2 changes: 0 additions & 2 deletions 1.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,3 @@
* 上一节: [PHP的生命周期](<1.md>)
* 下一节: [PHP的启动与终止](<1.2.md>)

## LastModified
* $Id$
22 changes: 20 additions & 2 deletions 1.2.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
# 1.2 PHP的启动与终止

<<<<<<< HEAD
PHP程序的启动可以看作有两个概念上的启动,终止也有两个概念上的终止。其中一个是PHP作为Apache(拿它举例,板砖勿扔)的一个模块的启动与终止,这次启动php会初始化一些必要数据,比如与宿主Apache有关的,<b>并且这些数据是常驻内存的!</b>终止与之相对。还有一个概念上的启动就是当Apache分配一个页面请求过来的时候,PHP会有一次启动与终止,这也是我们最常讨论的一种。
现在我们主要来看一个PHP扩展的生命旅程是怎样走完这四个过程的。
在最初的初始化时候,就是PHP随着Apache的启动而诞生在内存里的时候,它会把自己所有已加载扩展的MINIT方法(俗称Module Initialization,模块初始化?其实是个函数)都执行一遍。在这个时间里,扩展可以定义一些自己的常量、类、资源等所有会被用户端的PHP脚本用到的东西。但你要记住,这里定义的东东都会随着Apache常驻内存,可以被所有请求使用,直到Apache卸载掉PHP模块!
=======
PHP程序的启动可以看作有两个概念上的启动,终止也有两个概念上的终止。其中一个是PHP作为Apache(拿它举例,板砖勿扔)的一个模块的启动与终止,这次启动php会初始化一些必要数据,比如与宿主Apache有关的,<b>并且这些数据是常驻内存的!</b>,终止与之相对。还有一个概念上的启动就是当Apache分配过一个页面请求来的时候,PHP会有一次启动与终止,这也是我们最常讨论的一种。

现在我们主要来看一个PHP扩展的生命旅程是怎样走完这四个过程的。

在最初的初始化时候,就是PHP随着Apache的启动而诞生在内存里的时,它会把自己所有已加载扩展的MINIT方法(俗称Module Initialization,模块初始化?其实是个函数)都执行一遍。在这个时间里,扩展可以定义一些自己的常量、类、资源等所有会被用户端的PHP脚本用到的东西。但你要记住,这里定义的东东都会随着Apache常驻内存,可以被所有请求使用,直到Apache卸载掉PHP模块!

>>>>>>> 7826efeca875ee99cadd2e2ff5e7b0ea5823feff
内核中预置了PHP_MINIT_FUNCTION宏函数,来帮助我们实现这个功能:
````c
//抛弃作者那个例子,书才看两页整那样的例子太复杂了!
Expand All @@ -25,7 +34,12 @@ PHP_RINIT_FUNCTION(walu)
}
````
<<<<<<< HEAD
好了,现在这个页面请求执行的差不多了,可能是顺利的走到了自己文件的最后,也可能是出师未捷,半道被用户给die或者exit了,这时候PHP便会启动回收程序,收拾这个请求留下的烂摊子。它这次会执行所有已加载扩展的RSHUTDOWN(俗称Request Shutdown)方法,这时候扩展可以抓紧利用内核中的变量表之类的做一些事情,因为一旦PHP把所有扩展的RSHUTDOWN方法执行完,便会释放掉这次请求使用过的所有东西,包括变量表的所有变量、所有在这次请求中申请的内存等等。
=======
好了,现在这个页面请求执行的差不多了,可能是顺利的走到了自己文件的最后,也可能是出师未捷,半道被用户给die或者exit了,这时候PHP便会启动回收程序,收拾这个请求留下的烂摊子。它这次会执行所有已加载扩展的RSHUTDOWN(俗称Request Shutdown)方法,这时候扩展可以抓紧利用内核中的变量表啊之类的做一些事情,因为一旦PHP把所有扩展的RSHUTDOWN方法执行完,便会释放掉这次请求使用过的所有东西,包括变量表的所有变量、所有在这次请求中申请的内存等等。

>>>>>>> 7826efeca875ee99cadd2e2ff5e7b0ea5823feff
内核预置了PHP_RSHUTDOWN_FUNCTION宏函数来帮助我们实现这个功能
````c
PHP_RSHUTDOWN_FUNCTION(walu)
Expand All @@ -37,7 +51,12 @@ PHP_RSHUTDOWN_FUNCTION(walu)
}

````
<<<<<<< HEAD
前面该启动的也启动了,该结束的也结束了,现在该Apache老人家歇歇的时候,当Apache通知PHP自己要Stop的时候,PHP便进入MSHUTDOWN(俗称Module Shutdown)阶段。这时候PHP便会给所有扩展下最后通牒,如果哪个扩展还有未了的心愿,就放在自己MSHUTDOWN方法里,这可是最后的机会了,一旦PHP把扩展的MSHUTDOWN执行完,便会进入自毁程序,这里一定要把自己擅自申请的内存给释放掉,否则就杯具了。
=======
前面该启动的也启动了,该结束的也结束了,现在该Apache老人家歇歇的时候,当Apache通知PHP自己要Stop的时候,PHP便进入MSHUTDOWN(俗称Module Shutdown)阶段。这时候PHP便会给所有扩展下最后通喋,如果哪个扩展还有未了的心愿,就放在自己MSHUTDOWN方法里,这可是最后的机会了,一旦PHP把扩展的MSHUTDOWN执行完,便会进入自毁程序,这里一定要把自己擅自申请的内存给释放掉,否则就杯具了。
>>>>>>> 7826efeca875ee99cadd2e2ff5e7b0ea5823feff
内核中预置了PHP_MSHUTDOWN_FUNCTION宏函数来帮助我们实现这个功能:
````c
PHP_MSHUTDOWN_FUNCTION(walu)
Expand All @@ -49,6 +68,7 @@ PHP_MSHUTDOWN_FUNCTION(walu)
````
这四个宏都是在walu.c里完成最终实现的,而他们的则是在/main/php.h里被定义的(其实也是调用的别的宏,本节最后我把这几个宏给展开了,供有需要的人查看)。

<b>好了,现在我们本节内容说完了,下面我们把所有的代码合在一起,并预测一下应该出现的结果:</b>
````c
//这些代码都在walu.c里面,不再.h里
Expand Down Expand Up @@ -107,5 +127,3 @@ PHP_FUNCTION(walu_test)
* 上一节: [让我们从SAPI开始](<1.1.md>)
* 下一节: [PHP的生命周期](<1.3.md>)
## LastModified
* $Id$
42 changes: 33 additions & 9 deletions 1.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
<li>多线程模块</li>
<li>Embedded(嵌入式,在自己的C程序中调用Zend Engine)</li>
</ul>

## 1、CLI/CGI时的周期

CLI和CGI的SAPI是相当特殊的,因为这时PHP的生命周期完全在一个单独的请求中完成。虽然简单,不过我们以前提过的两种init和两种shutdown仍然都会被执行。图1.1展示了PHP在这种模式下是怎么工作的。
<<<<<<< HEAD
<p style="text-align:center"><img src="http://www.walu.cc/phpbook/image/01fig01.jpg" />
## 2、多进程模式下
<span class="ps">[ps:书是2006年出版的,所以你应该理解作者说多进程是主流]</span>PHP最常见的工作方式便是编译成为Apache2 的Pre-fork MPM或者Apache1 的APXS 模式,其它web服务器也大多用相同的方式工作,在本书后面,把这种方式统一叫做多进程方式。给它起这个名字是有原因的,不是随便拍拍屁股拍拍脑袋定下来的。当Apache启动的时候,会立即把自己fork出好几个子进程,每一个进程都有自己独立的内存空间,也就代表了有自己独立的变量、函数等。在每个进程里的PHP的工作方式如下图所示:
Expand All @@ -20,20 +23,41 @@ CLI和CGI的SAPI是相当特殊的,因为这时PHP的生命周期完全在一
<p style="text-align:center"><img src="http://www.walu.cc/phpbook/image/01fig04.jpg" />
## 4、Embed
Embed SAPI是一种比较特殊的sapi,容许你在C/C++语言中调用PHP/ZE提供的函数。并且这种sapi和上面的三种一样,按Module Init、Request Init、Rshutdown、mshutdown的流程执行着。 当然,这只是其中一种情况。因为特定的应用有自己特殊的需求,只是在处理PHP脚本这个环节基本一致。
=======

<center><img src="image/01fig01.jpg" /></center>

## 2、多进程模式下
<span class="ps">[ps:书是2006年出版的,所以你应该理解作者说多进程是主流]</span>PHP最常见的工作方式便是编译成为Apache2 的Pre-fork MPM或者Apache1 的APXS 模式,其它web服务器也大多用相同的方式工作,在本书后面,把这种方式统一叫做多进程方式。给它起这个名字是有原因的,不是随便拍拍屁股拍拍脑袋定下来的。当Apache启动的时候,会立即把自己fork出好几个子进程,每一个进程都有自己独立的内存空间,也就代表了有自己独立的变量、函数等。在每个进程里的PHP的工作方式如下图所示:

<center><img src="image/01fig02.jpg" /></center>

因为是fork出来的,所以各个进程间的数据是无法直接相互影响的,无法读也无法写<span class="ps">(ps:fork后可以用管道等方式实现进程间通信)</span>。它允许每个子进程几乎可以做任何事情,玩七十码、躲猫猫都没人管,办公室拿砍刀玩自杀也没事,但是人家不一样的是人家有个前提:不能影响其它进程的稳定!下图展示了从apache的视角来看多进程工作模式下的PHP:

<center><img src="image/01fig03.jpg" /></center>

## 3、多线程模式下

随着时代的进步,PHP越来越多的在多线程模式下工作,就像IIS的isapi和Apache MPM worker<span class="ps">(支持混合的多线程多进程的多路处理模块)</span>。在这种模式下,只有一个服务器进程在运行着,但会同时运行很多线程,这样可以减少一些资源开销,向Module init和Module shutdown就只需要运行一遍就行了,一些全局变量也只需要初始化一次,因为线程独具的特质,使得各个请求之间方便的共享一些数据成为可能。下图展示了在这种模式下PHP的工作流程:

<center><img src="image/01fig04.jpg" /></center>

## 4、Embed
Embed SAPI是一种比较特殊的sapi,容许你在C/C++语言中调用PHP/ZE提供的函数。并且这种sapi和上面的三种一样,按Module Init、Request Init、Rshutdown、mshutdown的流程执行着。 当然,这只是其中一种情况。因为特定的应用由自己特殊的需求,只是在处理PHP脚本这个环节基本一致。

>>>>>>> 7826efeca875ee99cadd2e2ff5e7b0ea5823feff
真正令emebed模式独特的是因为它可能随时嵌入到某个程序里面去(<span class="ps">比如你的test.exe里</span>),然后被当作脚本的一部分在一个请求的时候执行。控制权在PHP和原程序间来回传递。关于嵌入式的PHP在第20章会有应用,到时我们再用实例介绍这个不经常使用的sapi。
<aside>
<hr />
关于Embed SAPI应用的文章
<ul>
<li> [Laruence大哥的使用PHP Embed SAPI实现Opcodes查看器](http://www.laruence.com/2008/09/23/539.html) </li>
</ul>
</aside>

<hr />
## 关于Embed SAPI应用的文章
* [Laruence大哥的使用PHP Embed SAPI实现Opcodes查看器](http://www.laruence.com/2008/09/23/539.html) </li>




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

## LastModified
* $Id$
13 changes: 11 additions & 2 deletions 1.4.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
# 1.4 PHP的生命周期

## 这一节没有翻译完,而且应该把这一节挪到后面的某一节里去

在PHP初期,是作为单进程的CGI来运行的,所以并没有考虑线程安全问题。我们可以随意的在全局作用域中设置变量并在程序中对他进行修改、访问,内核申请的资源如果没有正确的释放,也会在CGI进程结束后自动地被清理干净。

然后,php被作为apache多进程模式下的一个模块运行,但是这仍然把php局限在一个进程里,我们设置的全局变量,只要在每个请求之前将其正确的初始化,并在每个请求之后正确的清理干净,便不会带来什么麻烦。由于对于一个进程来说,同一个时间只能处理一个请求,所以这是内核中加入了针对每个请求的内存管理功能,来防止服务器资源利用出现错误。
现在,一个进程多个线程的工作方式被越来越多的采用,所以,php内核中亟需一种新的资源管理方式,其最终在php内核中形成了一个新的抽象层:TSRM(Thread Safe Resource Management)。

## 线程安全与非线程安全

在一个没有线程的程序中,我们往往倾向于把全局变量声明在源文件的顶部,编辑器会自动的为它分配资源供我们在声明语句之下的程序逻辑中使用。<span class="ps">(即使通过fork()出一个子进程,它也会重新申请一段内存,父子进程中的变量从此没有了任何联系)</span>
<<<<<<< HEAD
但是在一个多线程的程序中,如果我们需要每个线程都拥有自己独立的资源的话,便需要为每个线程独立开辟出一个区域来存放它们各自的资源,在线程里使用资源的时候,它便会去自己的那一亩三分地里去找,而不会拔了别人的庄稼。
=======

但是在一个多线程的程序中,如果我们需要每个线程都用有自己独立的资源的话,便需要为每个线程独立开辟出一个区域来存放它们各自的资源,在线程里使用资源的时候,它便会去自己的那一亩三分地里去找,而不会拔了别人的庄稼。

>>>>>>> 7826efeca875ee99cadd2e2ff5e7b0ea5823feff
## Thread-Safe Data Pools(线程安全的资源池?)

在扩展的Module Init里,扩展可以调用ts_allocate_id()来告诉TRSM自己需要多少资源,TRSM接收后更新系统使用的资源,并得到一个指向刚分配的那份资源的id。
````c
typedef struct {
Expand All @@ -33,5 +44,3 @@ PHP_MINIT_FUNCTION(sample)
* 上一节: [PHP的生命周期](<1.3.md>)
* 下一节: [小结](<1.5.md>)
## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 1.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,3 @@
* 上一节: [线程安全](<1.4.md>)
* 下一节: [PHP变量在内核中的实现](<2.md>)

## LastModified
* $Id$
13 changes: 6 additions & 7 deletions 1.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
# 1 PHP的生命周期

## 目录
* 1. [让我们从SAPI开始](1.1.html)
* 2. [PHP的启动与终止](1.2.html)
* 3. [PHP的生命周期](1.3.html)
* 4. [线程安全](1.4.html)
* 5. [小结](1.5.html)
* 1. [让我们从SAPI开始](1.1.md)
* 2. [PHP的启动与终止](1.2.md)
* 3. [PHP的生命周期](1.3.md)
* 4. [线程安全](1.4.md)
* 5. [小结](1.5.md)

在平常的Web环境中,我们并不需要单独启动PHP,它一般都会作为一个模块自动加载到web-server里面去,如apache加载的php5.so。只要我们启动了web-server,被一起加载的php便会和服务器一起解析被请求的php脚本。

当然,这不是绝对的,当我们以fastcgi模式安装php的时候,往往就需要手动在终端运行php -b 127.0.0.1:9999来启动php,这个命令只是个例子,可能你的和我的并不一样。没记错的话,我的应该是我在fedora15上配置nginx+php时的一条命令。

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

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 10.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,3 @@ $obj = new myclass();
* 10 [PHP中的面向对象(一)](<10.md>)
* 10.2 [定义一个类](<10.2.md>)

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 10.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,3 @@ ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char
* 10.1 [zend_class_entry](<10.1.md>)
* 10.3 [定义一个接口](<10.3.md>)

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 10.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,3 @@ $obj->hello();
* 10.2 [定义一个类](<10.2.md>)
* 10.4 [继承与实现接口](<10.4.md>)

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 10.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,3 @@ static zend_function_entry i_myinterface[]=
* 10.3 [定义一个接口](<10.3.md>)
* 10.5 [小结](<10.5.md>)

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 10.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@
* 10.4 [继承与实现接口](<10.4.md>)
* 11 [PHP中的面向对象(二)](<11.md>)

## LastModified
* $Id$
15 changes: 6 additions & 9 deletions 10.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
# 10 PHP中的面向对象(一)

<ul class="catalog">
<li> [1. zend_class_entry](ch10.1.html) </li>
<li> [2. 定义一个类](ch10.2.html) </li>
<li> [3. 定义一个接口](ch10.3.html) </li>
<li> [4. 类的继承与接口的实现](ch10.4.html) </li>
<li> [5. 小结](ch10.5.html) </li>
</ul>
* [1. zend_class_entry](10.1.md)
* [2. 定义一个类](10.2.md)
* [3. 定义一个接口](10.3.md)
* [4. 类的继承与接口的实现](10.4.md)
* [5. 小结](10.5.md)

面向对象的概念这里就不再叙述了。原书中把这一部分的知识分开到PHP4和PHP5中来讲的,这里我做了大幅的调整,几乎是进行了重写。前一部分主要介绍了如何定义类、接口等一些声明类的操作。后一部分主要介绍了对象的使用等一些对实例的操作。


## links
* 9.4 [第九章小结](<9.4.md>)
* 10.1 [zend_class_entry](<10.1.md>)

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 11.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,3 @@ ZEND_MINIT_FUNCTION(test)
* 11 [PHP中的面向对象(二)](<11.md>)
* 11.2 [读写对象的属性](<11.2.md>)
## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 11.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,3 @@ ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, char *
* 11.1 [生成对象的实例](<11.1.md>)
* 11.3 [小结](<11.3.md>)
## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 11.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,3 @@
* 11.2 [读写对象的属性](<11.2.md>)
* 0 []()

## LastModified
* $Id$
12 changes: 5 additions & 7 deletions 11.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# 11 PHP中的面向对象(二)

<ul class="catalog">
<li> [1. 生成对象的实例与调用方法](ch11.1.html) </li>
<li> [2. 读写对象的属性](ch11.2.html) </li>
<li> [3. 小结](ch11.3.html) </li>
</ul>

* [1. 生成对象的实例与调用方法](11.1.md)
* [2. 读写对象的属性](11.2.md)
* [3. 小结](11.3.md)

上一章里,我们看了一下如何在PHP扩展里定义类与接口,那这一章里我们将入手一下如何在PHP扩展中操作类的实例————对象。
PHP语言中的面向对象其实是分为三个部分来实现的,class、object、refrence。class就是我们所说的类,可以直观的理解为前面章节中所描述的zend_class_entry。object就是实际的对象。每一个zval并不直接包含具体的object,而是通过一个索引--refrence与其联系。也就是说,每个class都有很多个object实例,并把他们统一的放在一个数组里,每个zval只要记住自己相应的key就行了。如此一来,我们在传递zval时候,实际上传递的是一个索引,而不是内存中具体的对象数据。

Expand All @@ -13,5 +13,3 @@ PHP语言中的面向对象其实是分为三个部分来实现的,class、obj
* 10.5 [小结](<10.5.md>)
* 11.1 [生成对象的实例](<11.1.md>)

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 12.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,3 @@ EG( persistent_list ) HashTable中的持久性资源,因为他们往往​
* 上一节: [启动与终止的那点事](<12.md>)
* 下一节: [MINFO与phpinfo](<12.2.md>)

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 12.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,3 @@ PHP_MINFO_FUNCTION(sample4) {
* 12.1 [关于生命周期](<12.1.md>)
* 12.3 [常量](<12.1.md>)
## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 12.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,3 @@ void php_sample4_register_boolean_constant(char *name, uint len,
* 12.2 [MINFO与phpinfo](<12.2.md>)
* 12.4 [常量](<12.4.md>)
## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 12.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,3 @@ FG() | 文件全局变量。大多数文件I/O或相关的全局变量的数据
* 12.3 [常量](<12.3.md>)
* 12.5 [PHP语言中的超级全局变量](<12.5.md>)
## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 12.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,3 @@ PHP_RINIT_FUNCTION(sample4) {
* 12.4 [PHP扩展中的全局变量](<12.4.md>)
* 12.6 [小结](<12.6.md>)
## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 12.6.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@
* 12.5 [PHP语言中的超级全局变量](<12.5.md>)
* 13.md [设置INI](<13.md>)

## LastModified
* $Id$
2 changes: 0 additions & 2 deletions 12.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,3 @@
* 11.3 [小结](<11.3.md>)
* 12.1 [关于生命周期](<12.1.md>)

## LastModified
* $Id$
Loading

0 comments on commit aa17971

Please sign in to comment.