Skip to content

Commit

Permalink
校正第二章及第一章的一些bug
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] committed Dec 23, 2012
1 parent 6600ef5 commit c52a507
Show file tree
Hide file tree
Showing 8 changed files with 21 additions and 21 deletions.
12 changes: 6 additions & 6 deletions 1.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@
</ul>
## 1、CLI/CGI时的周期
CLI和CGI的SAPI是相当特殊的,因为这时PHP的生命周期完全在一个单独的请求中完成。虽然简单,不过我们以前提过的两种init和两种shutdown仍然都会被执行。图1.1展示了PHP在这种模式下是怎么工作的。
<p style="text-align:center"><img src="image/01fig01.jpg" />
<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的工作方式如下图所示:
<p style="text-align:center"><img src="image/01fig02.jpg"
<p style="text-align:center"><img src="http://www.walu.cc/phpbook/image/01fig02.jpg"
因为是fork出来的,所以各个进程间的数据是无法直接相互影响的,无法读也无法写<span class="ps">(ps:fork后可以用管道等方式实现进程间通信)</span>。它允许每个子进程几乎可以做任何事情,玩七十码、躲猫猫都没人管,办公室拿砍刀玩自杀也没事,但是人家不一样的是人家有个前提:不能影响其它进程的稳定!下图展示了从apache的视角来看多进程工作模式下的PHP:
<p style="text-align:center"><img src="image/01fig03.jpg" />
<p style="text-align:center"><img src="http://www.walu.cc/phpbook/image/01fig03.jpg" />
## 3、多线程模式下
随着时代的进步,PHP越来越多的在多线程模式下工作,就像IIS的isapi和Apache MPM worker<span class="ps">(支持混合的多线程多进程的多路处理模块)</span>。在这种模式下,只有一个服务器进程在运行着,但会同时运行很多线程,这样可以减少一些资源开销,向Module init和Module shutdown就只需要运行一遍就行了,一些全局变量也只需要初始化一次,因为线程独具的特质,使得各个请求之间方便的共享一些数据成为可能。下图展示了在这种模式下PHP的工作流程:
<p style="text-align:center"><img src="image/01fig04.jpg" />
随着时代的进步,PHP越来越多的在多线程模式下工作,就像IIS的isapi和Apache MPM worker<span class="ps">(支持混合的多线程多进程的多路处理模块)</span>。在这种模式下,只有一个服务器进程在运行着,但会同时运行很多线程,这样可以减少一些资源开销,像Module init和Module shutdown就只需要运行一次就行了,一些全局变量也只需要初始化一次,因为线程独具的特质,使得各个请求之间方便的共享一些数据成为可能。下图展示了在这种模式下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脚本这个环节基本一致。
Embed SAPI是一种比较特殊的sapi,容许你在C/C++语言中调用PHP/ZE提供的函数。并且这种sapi和上面的三种一样,按Module Init、Request Init、Rshutdown、mshutdown的流程执行着。 当然,这只是其中一种情况。因为特定的应用有自己特殊的需求,只是在处理PHP脚本这个环节基本一致。
真正令emebed模式独特的是因为它可能随时嵌入到某个程序里面去(<span class="ps">比如你的test.exe里</span>),然后被当作脚本的一部分在一个请求的时候执行。控制权在PHP和原程序间来回传递。关于嵌入式的PHP在第20章会有应用,到时我们再用实例介绍这个不经常使用的sapi。

<aside>
Expand Down
2 changes: 1 addition & 1 deletion 1.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
现在,一个进程多个线程的工作方式被越来越多的采用,所以,php内核中亟需一种新的资源管理方式,其最终在php内核中形成了一个新的抽象层:TSRM(Thread Safe Resource Management)。
## 线程安全与非线程安全
在一个没有线程的程序中,我们往往倾向于把全局变量声明在源文件的顶部,编辑器会自动的为它分配资源供我们在声明语句之下的程序逻辑中使用。<span class="ps">(即使通过fork()出一个子进程,它也会重新申请一段内存,父子进程中的变量从此没有了任何联系)</span>
但是在一个多线程的程序中,如果我们需要每个线程都用有自己独立的资源的话,便需要为每个线程独立开辟出一个区域来存放它们各自的资源,在线程里使用资源的时候,它便会去自己的那一亩三分地里去找,而不会拔了别人的庄稼。
但是在一个多线程的程序中,如果我们需要每个线程都拥有自己独立的资源的话,便需要为每个线程独立开辟出一个区域来存放它们各自的资源,在线程里使用资源的时候,它便会去自己的那一亩三分地里去找,而不会拔了别人的庄稼。
## Thread-Safe Data Pools(线程安全的资源池?)
在扩展的Module Init里,扩展可以调用ts_allocate_id()来告诉TRSM自己需要多少资源,TRSM接收后更新系统使用的资源,并得到一个指向刚分配的那份资源的id。
````c
Expand Down
12 changes: 6 additions & 6 deletions 2.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ typedef unsigned int zend_uint;
typedef unsigned char zend_uchar;

````
zval里的refcout__gc是zend_uint类型,也就是unsinged int型,is_ref__gc和type则是unsigned char型的。<br />保存变量值的value则是zvalue_value类型(PHP5),它是一个Union,同样定义在了Zend/zend.h文件里:
zval里的refcout__gc是zend_uint类型,也就是unsigned int型,is_ref__gc和type则是unsigned char型的。<br />保存变量值的value则是zvalue_value类型(PHP5),它是一个Union,同样定义在了Zend/zend.h文件里:
````c
typedef union _zvalue_value {
long lval; /* long value */
Expand All @@ -37,15 +37,15 @@ typedef union _zvalue_value {
</tr>
<tr>
<td>IS_NULL</td>
<td>第一次使用的变量如果没有初始化过,则会自动的赋予这个变量,当然我们也可以在PHP语言中通过null这个常量来给予变量null类型的值。 这个类型的值只有一个 ,就是NULL,它和0与false是不同的。</td>
<td>第一次使用的变量如果没有初始化过,则会自动的被赋予这个常量,当然我们也可以在PHP语言中通过null这个常量来给予变量null类型的值。 这个类型的值只有一个 ,就是NULL,它和0与false是不同的。</td>
</tr>
<tr>
<td>IS_BOOL</td>
<td>布尔类型的变量有两个值,true或者false。在PHP语言中,while、if等语句会自动的把表达式的值转成这个类型的。</td>
</tr>
<tr>
<td>IS_LONG</td>
<td>PHP语言中的整型,在内核中是通过所在操作系统的singed long数据类型来表示的。在最常见的32位操作系统中,它可以存储从-2147483648 到 +2147483647范围内的任一整数。有一点需要注意的是,如果PHP语言中的整型变量超出最大值或者最小值,它并不会直接溢出,而是会被内核转换成IS_DOUBLE类型的值然后再参与计算。再者,因为使用了singed long来作为载体,所以这也就解释了为什么PHP语言中的整型数据都是带符号的了。
<td>PHP语言中的整型,在内核中是通过所在操作系统的signed long数据类型来表示的。在最常见的32位操作系统中,它可以存储从-2147483648 到 +2147483647范围内的任一整数。有一点需要注意的是,如果PHP语言中的整型变量超出最大值或者最小值,它并不会直接溢出,而是会被内核转换成IS_DOUBLE类型的值然后再参与计算。再者,因为使用了signed long来作为载体,所以这也就解释了为什么PHP语言中的整型数据都是带符号的了。
<br /><code c>
$a=2147483647;
$a++;
Expand All @@ -54,11 +54,11 @@ echo $a;//会正确的输出 2147483648;
</tr>
<tr>
<td>IS_DOUBLE</td>
<td>PHP中的浮点数据是通过C语言中的singed double型变量来存储的,这最终取决与所在操作系统的浮点型实现。 我们做为程序猿,应该知道计算机是无法精准的表示浮点数的,而是采用了科学计数法来保存某个精度的浮点数。用科学计数法,计算机只用8位便可以保存2.225x10^(-308)1.798x10^308之间的浮点数。用计算机来处理浮点数简直就是一场噩梦,十进制的0.5专成二进制是0.1,0.8转换后是0.1100110011....。但是当我们从二进制转换回来的时候,往往会发现并不能得到0.8。我们用1除以3这个例子来解释这个现象:1/3=0.3333333333.....,它是一个无限循环小数,但是计算机可能只能精确存储到0.333333,当我们再乘以三时,其实计算机计算的数是0.333333*3=0.999999,而不是我们平时数学中所期盼的1.0.</td>
<td>PHP中的浮点数据是通过C语言中的signed double型变量来存储的,这最终取决与所在操作系统的浮点型实现。 我们做为程序猿,应该知道计算机是无法精准的表示浮点数的,而是采用了科学计数法来保存某个精度的浮点数。用科学计数法,计算机只用8位便可以保存2.225x10^(-308)~~1.798x10^308之间的浮点数。用计算机来处理浮点数简直就是一场噩梦,十进制的0.5专成二进制是0.1,0.8转换后是0.1100110011....。但是当我们从二进制转换回来的时候,往往会发现并不能得到0.8。我们用1除以3这个例子来解释这个现象:1/3=0.3333333333.....,它是一个无限循环小数,但是计算机可能只能精确存储到0.333333,当我们再乘以三时,其实计算机计算的数是0.333333*3=0.999999,而不是我们平时数学中所期盼的1.0.</td>
</tr>
<tr>
<td>IS_STRING</td>
<td>PHP中最常用的数据类型——字符串,在内存中的存储和C差不多,就是一块能够放下这个变量所有字符的内存,并且在这个变量的zval实现里会保存着指向这块内存的指针。与C不同的是,PHP内核还同时在zval结构里保存着这个字符串的实际长度,这个设计使PHP可以在字符串中嵌入‘\0’字符,也使PHP的字符串是二进制安全的,可以安全的存储二进制数据!本着艰苦朴素的作风,内核只会为字符串申请它长度+1的内存,最后一个字节存储的是‘\0’字符,所以在不需要二进制安全操作的时候,我们可以像通常C语言的概念那样来使用它。</td>
<td>PHP中最常用的数据类型——字符串,在内存中的存储和C差不多,就是一块能够放下这个变量所有字符的内存,并且在这个变量的zval实现里会保存着指向这块内存的指针。与C不同的是,PHP内核还同时在zval结构里保存着这个字符串的实际长度,这个设计使PHP可以在字符串中嵌入‘\0’字符,也使PHP的字符串是二进制安全的,可以安全的存储二进制数据!本着艰苦朴素的作风,内核只会为字符串申请它长度+1的内存,最后一个字节存储的是‘\0’字符,所以在不需要二进制安全操作的时候,我们可以像通常C语言的方式那样来使用它。</td>
</tr>
<tr>
<td>IS_ARRAY</td>
Expand Down Expand Up @@ -89,7 +89,7 @@ void describe_zval(zval *foo)
}

````
<p style="color:red">上述做法看起来没有错误,但它是一种被强烈禁止一种做法
<p style="color:red">上述做法看起来没有错误,但它是一种被强烈禁止的做法
PHP内核以后可能会修改变量的实现方式,所以检测type的方法可能在以后就不能用了。为了解决这个兼容问题,zend头文件中定义了大量的宏,供我们检测、操作变量使用,使用这些宏不但让我们的程序更易读,还具有更好的兼容性。这里我们用Z_TYPE_P()宏来改写上面那个程序。
<pre class="code">
void describe_zval(zval *foo)
Expand Down
8 changes: 4 additions & 4 deletions 2.3.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# 2.3 第二章目录

我们已经知道php变量在内核中其实是通过zval结构来实现的,也初步了如果设置一个zval结构的类型和值,这一节我们的目的便是在前两节的基础上,彻底掌握对zval结构的操控,其间将引入很多超棒的新的宏。
在code的时候,我们很希望在内核中创建的zval可以让用户在PHP语言里以变量的形式使用,为了实现这个功能,我们首先要创建一个zval。最容易想到的办法便是创建一个zval指针,然后申请一块内存并让指针指向它。如果你脑海里浮现出了malloc(sizeof(zval))的影子,那么请你立即刹车,不要用malloc来做这件事情,内核给我们提供了相应的宏来处理这件事,理由和以前一样:为了代码漂亮并保持版本升级时的兼容性。这个宏的是:MAKE_STD_ZVAL(pzv)。这个宏会用内核的方式来申请一块内存并将其地址付给pzv,并初始化它的refcount和is_ref连个属性,更棒的是,它不但会自动的处理内存不足问题,还会在内存中选个最优的位置来申请。
我们已经知道php变量在内核中其实是通过zval结构来实现的,也初步了解如何设置一个zval结构的类型和值,这一节我们的目的便是在前两节的基础上,彻底掌握对zval结构的操控,其间将引入很多超棒的新的宏。
在code的时候,我们很希望在内核中创建的zval可以让用户在PHP语言里以变量的形式使用,为了实现这个功能,我们首先要创建一个zval。最容易想到的办法便是创建一个zval指针,然后申请一块内存并让指针指向它。如果你脑海里浮现出了malloc(sizeof(zval))的影子,那么请你立即刹车,不要用malloc来做这件事情,内核给我们提供了相应的宏来处理这件事,理由和以前一样:为了代码漂亮并保持版本升级时的兼容性。这个宏是:MAKE_STD_ZVAL(pzv)。这个宏会用内核的方式来申请一块内存并将其地址付给pzv,并初始化它的refcount__gc和is_ref__gc两个属性,更棒的是,它不但会自动的处理内存不足问题,还会在内存中选个最优的位置来申请。
<p class="note">除了MAKE_STD_ZVAL()宏函数,ALLOC_INIT_ZVAL()宏函数也是用来干这件事的,唯一的不同便是它会将pzv所指的zval的类型设置为IS_NULL;
申请完空间后,我们便可以给这个zval赋值了。基于咱已经介绍的宏,也许我们需要Z_TYPE_P(p) = IS_NULL来设置其是null类型,并过Z_SOMEVAL形式的宏来为它赋值,但是现在你有了更好更短的选择
申请完空间后,我们便可以给这个zval赋值了。基于咱已经介绍的宏,也许我们需要Z_TYPE_P(p) = IS_NULL来设置其是null类型,并通过Z_SOMEVAL形式的宏来为它赋值,但是现在你有了更好更简洁的选择
内核中提供一些宏来简化我们的操作,可以只用一步便设置好zval的类型和值。
<table class="table-common">
<tr>
Expand Down Expand Up @@ -53,7 +53,7 @@
### ZVAL_STRINGL(pzv,str,len,dup)中的dup参数
先阐述一下ZVAL_STRINGL(pzv,str,len,dup); str和len两个参数很好理解,因为我们知道内核中保存了字符串的地址和它的长度,后面的dup的意思其实很简单,它指明了该字符串是否需要被复制。值为 1 将先申请一块新内存并赋值该字符串,然后把新内存的地址复制给pzv,为 0 时则是直接把str的地址赋值给zval。《抚琴居》上的一篇文章说这项特性将会在你仅仅需要创建一个变量并将其指向一个已经由 Zend 内部数据内存时变得很有用。
### ZVAL_STRINGL与ZVAL_STRING的区别
如果你想在某一位置截取该字符串或已经知道了这个字符串的长度,那么可以使用宏 ZVAL_STRINGL(zval, string, length, duplicate) ,它显示的指定字符串长度,而不是使用strlen()。这个宏该字符串长度作为参数。但它是二进制安全的,而且速度也比ZVAL_STRING快,因为少了个strlen。
如果你想在某一位置截取该字符串或已经知道了这个字符串的长度,那么可以使用宏 ZVAL_STRINGL(zval, string, length, duplicate) ,它显示的指定字符串长度,而不是使用strlen()。这个宏将字符串长度作为参数。但它是二进制安全的,而且速度也比ZVAL_STRING快,因为少了个strlen。
### ZVAL_RESOURCE约等于ZVAL_LONG
上一节中我们说过PHP中的资源类型的值其实就是一个整数,所以ZVAL_RESOURCE和ZVAL_LONG的工作差不多,只不过它会把zval的类型设置为 IS_RESOURCE.

Expand Down
2 changes: 1 addition & 1 deletion 2.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ $foo = 'bar';
ZVAL_STRING(fooval, "bar", 1);
ZEND_SET_SYMBOL( EG(active_symbol_table) , "foo" , fooval);
}

````

首先,我们声明一个zval指针,并申请一块内存。然后通过ZVAL_STRING宏将值设置为‘bar’,最后一行的作用就是将这个zval加入到当前的符号表里去,并将其label定义成foo,这样用户就可以在代码里通过$foo来使用它了。


Expand Down
2 changes: 1 addition & 1 deletion 2.5.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 2.5 第二章目录

用户在PHP语言里定义的变量,我们能否在内核中获取到呢?答案当然是肯定的,下面我们就看如何通过zend_hash_find()函数来找到当前某个作用域下用户已经定义好的变量。zend_hash_find()函数是内核提供的操作HashTable的API之一,如果你没有接触过,可以先记住这么使用就可以了
用户在PHP语言里定义的变量,我们能否在内核中获取到呢?答案当然是肯定的,下面我们就看如何通过zend_hash_find()函数来找到当前某个作用域下用户已经定义好的变量。zend_hash_find()函数是内核提供的操作HashTable的API之一,如果你没有接触过,可以先记住怎么使用就可以了
````c
{
zval **fooval;
Expand Down
2 changes: 1 addition & 1 deletion 2.6.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 2.6 第二章目录

现在我们已经可以从符号表中获取用户在PHP语言里定义的变量了,是该做点其它事的时候了,举个比例,比如给它来个类型转换:-)。想想C语言中的类型转换细则,你的头是不是已经大了?但是变量的类型转换就是如此重要,如果没有,那我们的代码就会是下面这样了:
现在我们已经可以从符号表中获取用户在PHP语言里定义的变量了,是该做点其它事的时候了,举个例子,比如给它来个类型转换:-)。想想C语言中的类型转换细则,你的头是不是已经大了?但是变量的类型转换就是如此重要,如果没有,那我们的代码就会是下面这样了:
````c
void display_zval(zval *value)
{
Expand Down
Loading

0 comments on commit c52a507

Please sign in to comment.