<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>风雪之隅 &#187; Zend/PHP</title>
	<atom:link href="http://www.laruence.com/tag/zendphp/feed" rel="self" type="application/rss+xml" />
	<link>http://www.laruence.com</link>
	<description>PHP语言, PHP扩展, Zend引擎相关的研究,技术,新闻分享 - 左手代码 右手诗</description>
	<lastBuildDate>Wed, 08 Feb 2012 05:12:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>使用PHP Embed SAPI实现Opcodes查看器</title>
		<link>http://www.laruence.com/2008/09/23/539.html</link>
		<comments>http://www.laruence.com/2008/09/23/539.html#comments</comments>
		<pubDate>Tue, 23 Sep 2008 08:58:09 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[embed]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SAPI]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=539</guid>
		<description><![CDATA[   PHP提供了一个Embed SAPI，也就是说，PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。
首先，下载PHP源码以供编译， 我现在使用的是PHP5.3 alpha2
进入源码目录：
<coolcode lang="shell" linenum="off">
 ./configure --enable-embed 
 ./make
 ./make install
</coolcode>
最后，记得要将生成的libphp5.so复制到运行时...]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/09/23/539.html"  title="Permanet Link to 使用PHP Embed SAPI实现Opcodes查看器" >http://www.laruence.com/2008/09/23/539.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>   PHP提供了一个Embed SAPI，也就是说，PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。<br/>
首先，下载PHP源码以供编译， 我现在使用的是PHP5.3 alpha2<br/>
进入源码目录：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
 ./configure --enable-embed --with-config-file-scan-dir=/etc/php.d --with-mysql  --with-config-file-path=/etc/
 ./make
 ./make install
</pre>
<p>最后，记得要将生成的libphp5.so复制到运行时库的目录，我直接拷贝到了/lib/, 否则会在运行你自己的embed程序的时候报错：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
./embed: error while loading shared libraries: libphp5.so: cannot open shared object file: No such file or directory
</pre>
<p> 如果你对PHP的SAPI还不熟悉的话，我建议你看看我的这篇文章：<a href="http://www.laruence.com/2008/08/12/180.html" >深入理解Zend SAPIs(Zend SAPI Internals)</a><br/>
 这个时候，你就可以在你的C代码中，嵌入PHP脚本解析器了， 我的例子：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
#include &quot;sapi/embed/php_embed.h&quot;

int main(int argc, char * argv[]){
    PHP_EMBED_START_BLOCK(argc,argv);
    char * script = &quot; print 'Hello World!';&quot;;
    zend_eval_string(script, NULL,
                                      &quot;Simple Hello World App&quot; TSRMLS_CC);
    PHP_EMBED_END_BLOCK();
    return 0;
}
 </pre>
<p> 然后就是要指明include path了，一个简单的Makefile</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
CC = gcc
CFLAGS = -I/usr/local/include/php/ \
            -I/usr/local/include/php/main \
            -I/usr/local/include/php/Zend \
            -I/usr/local/include/php/TSRM \
            -Wall -g
LDFLAGS = -lstdc++ -L/usr/local/lib -lphp5
ALL:
    $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)
</pre>
<p>编译成功以后， 运行，我们可以看到， stdout输出 Hello World！</p>
<p>基于这个，我们就可以很容易的实现一个类似于vld的Opcodes dumper：<br/>
首先我们定义opcode的转换函数（全部的opcodes可以查看Zend/zend_vm_opcodes.h）；</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
char *opname(zend_uchar opcode){
    switch(opcode) {
        case ZEND_NOP: return &quot;ZEND_NOP&quot;; break;
        case ZEND_ADD: return &quot;ZEND_ADD&quot;; break;
        case ZEND_SUB: return &quot;ZEND_SUB&quot;; break;
        case ZEND_MUL: return &quot;ZEND_MUL&quot;; break;
        case ZEND_DIV: return &quot;ZEND_DIV&quot;; break;
        case ZEND_MOD: return &quot;ZEND_MOD&quot;; break;
        case ZEND_SL: return &quot;ZEND_SL&quot;; break;
        case ZEND_SR: return &quot;ZEND_SR&quot;; break;
        case ZEND_CONCAT: return &quot;ZEND_CONCAT&quot;; break;
        case ZEND_BW_OR: return &quot;ZEND_BW_OR&quot;; break;
        case ZEND_BW_AND: return &quot;ZEND_BW_AND&quot;; break;
        case ZEND_BW_XOR: return &quot;ZEND_BW_XOR&quot;; break;
        case ZEND_BW_NOT: return &quot;ZEND_BW_NOT&quot;; break;
        /*...省略 ....*/
        default : return &quot;UNKNOW&quot;; break;
</pre>
<p> 然后定义zval和znode的输出函数：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
 char *format_zval(zval *z)
{
    static char buffer[BUFFER_LEN];
    int len;

    switch(z-&gt;type) {
        case IS_NULL:
            return &quot;NULL&quot;;
        case IS_LONG:
        case IS_BOOL:
            snprintf(buffer, BUFFER_LEN, &quot;%d&quot;, z-&gt;value.lval);
            return buffer;
        case IS_DOUBLE:
            snprintf(buffer, BUFFER_LEN, &quot;%f&quot;, z-&gt;value.dval);
            return buffer;
        case IS_STRING:
            snprintf(buffer, BUFFER_LEN, &quot;\&quot;%s\&quot;&quot;, z-&gt;value.str.val);
            return buffer;
        case IS_ARRAY:
        case IS_OBJECT:
        case IS_RESOURCE:
        case IS_CONSTANT:
        case IS_CONSTANT_ARRAY:
            return &quot;&quot;;
        default:
            return &quot;unknown&quot;;
    }
}

char * format_znode(znode *n){
    static char buffer[BUFFER_LEN];

    switch (n-&gt;op_type) {
        case IS_CONST:
            return format_zval(&amp;n-&gt;u.constant);
            break;
        case IS_VAR:
            snprintf(buffer, BUFFER_LEN, &quot;$%d&quot;,  n-&gt;u.var/sizeof(temp_variable));
            return buffer;
            break;
        case IS_TMP_VAR:
            snprintf(buffer, BUFFER_LEN, &quot;~%d&quot;,  n-&gt;u.var/sizeof(temp_variable));
            return buffer;
            break;
        default:
            return &quot;&quot;;
            break;
    }
}
 </pre>
<p>然后定义op_array的输出函数：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
void dump_op(zend_op *op, int num){
    printf(&quot;%5d  %5d %30s %040s %040s %040s\n&quot;, num, op-&gt;lineno,
            opname(op-&gt;opcode),
            format_znode(&amp;op-&gt;op1),
            format_znode(&amp;op-&gt;op2),
            format_znode(&amp;op-&gt;result)) ;
}

void dump_op_array(zend_op_array *op_array){
    if(op_array) {
        int i;
        printf(&quot;%5s  %5s %30s %040s %040s %040s\n&quot;, &quot;opnum&quot;, &quot;line&quot;, &quot;opcode&quot;, &quot;op1&quot;, &quot;op2&quot;, &quot;result&quot;);
        for(i = 0; i &lt; op_array-&gt;last; i++) {
            dump_op(&amp;op_array-&gt;opcodes[i], i);
        }
    }
}
</pre>
<p>最后，就是程序的主函数了：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
int main(int argc, char **argv){
    zend_op_array *op_array;
    zend_file_handle file_handle;

    if(argc != 2) {
        printf(&quot;usage:  op_dumper &lt;script&gt;\n&quot;);
        return 1;
    }
    PHP_EMBED_START_BLOCK(argc,argv);
    printf(&quot;Script: %s\n&quot;, argv[1]);
    file_handle.filename = argv[1];
    file_handle.free_filename = 0;
    file_handle.type = ZEND_HANDLE_FILENAME;
    file_handle.opened_path = NULL;
    op_array =  zend_compile_file(&amp;file_handle, ZEND_INCLUDE TSRMLS_CC);
    if(!op_array) {
        printf(&quot;Error parsing script: %s\n&quot;, file_handle.filename);
        return 1;
    }
    dump_op_array(op_array);
    PHP_EMBED_END_BLOCK();
    return 0;
}
</pre>
<p>编译，运行测试脚本(sample.php):<br/>
sample.php:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
   echo &quot;laruence&quot;;
</pre>
<p>命令：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
./opcodes_dumper  sample.php
</pre>
<p>得到输出结果(如果你对下面的结果很迷惑，那么建议你再看看我的这篇文章：<a href="http://www.laruence.com/2008/06/18/221.html" >深入理解PHP原理之Opcodes</a>）：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
Script: sample.php
opnum   line                         opcode                                      op1                                      op2                                   result
    0      2                      ZEND_ECHO                               &quot;laruence&quot;
    1      4                    ZEND_RETURN                                        1
</pre>
<p>呵呵，怎么样，是不是很好玩呢？<br/>
源码地址：<a href="http://code.google.com/p/opcodesdumper/" >http://code.google.com/p/opcodesdumper/</a><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html" >2008/09/25</a>, <a href="http://www.surfchen.org"  rel="external nofollow"  class="url" >surfchen</a> writes: google code的svn里还没源代码呢</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2008/09/25</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: svn: http://code.google.com/p/opcodesdumper/source/browse/#svn/trunk
放进去了</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2008/09/26</a>, snowrui writes: 学习消化中......</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2008/11/06</a>, Anonymous writes: fxgh</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2008/11/06</a>, Anonymous writes: 看不懂..菜啊</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/05/17</a>, <a href="http://hi.baidu.com/jackywdx"  rel="external nofollow"  class="url" >jackywdx</a> writes: 呵呵,终于看懂了.</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/09/08</a>, Leric writes: 连接时总是报一个错误:
opcodes_dumper.cpp:(.text+0x910): undefined reference to `php_embed_init'
opcodes_dumper.cpp:(.text+0x9e9): undefined reference to `php_embed_shutdown'
collect2: ld returned 1 exit status
make: *** [ALL] Error 1

没用C做过什么东西,也不知道该咋解决,还望博主指点迷津</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/09/08</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @leric 你需要用ZEND_API来修饰php_embed_init/shutdown. 符号可见性的问题.</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/10/02</a>, fybird writes: 我是在php_embed_init/shutdown 前加上了SAPI_SPI才通过的。ZEND_API不好使？不知道为什么</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/10/03</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 你是用的PHP5.3吧?
是5.3的一个bug</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/10/03</a>, fybird writes: 对,直接就下载了一个5.3 没想到有bug.</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/10/22</a>, ddouble writes: 到处找zend_api的资料，想把php解释器嵌入到c程序中，google上怎么也找不到。为啥zend网站上也没呢，还是完全没摸到门儿？

博主知道哪里有吗？zend api reference之类的文档，最好还有指南示例之类的文档。谢谢啦！</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/10/22</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @ddouble 文档工作做的不好...确实没有你想要的.</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/10/23</a>, ddouble writes: 现在已能够在c程序里嵌入php解释器，非常感谢，但还有几个问题不解，望赐教：

1.如何在嵌入的方式下指定自己的php.ini文件；
2.多个连续执行的 zend_eval_string之间无法延续变量作用域，所以前面的eval的变量，后面eval的语句中无法得到。</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/10/23</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 1. 编译的时候确定

2. 我不知道有什么办法, 或者你可以使用c的变量来做个中转. 在PHP_EMBED_START_BLOCK(argc,argv)中做为第二个参数的一部分传入, 通过SG(request_info).argv来访问.</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/11/23</a>, aaa110110 writes: 请问windows环境下面怎么得到opcode,以上代码怎么编译呢?</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/11/23</a>, qq347835460 writes: 替楼主回到楼上的:
下载vld扩展,用c++编译成dll,怎么编译,可以baidu之,或者自己研究,这个过程要下载php的源码包和二进制包(最好版本一致).
编译成了dll之后修改php.ini,加一行:
extension=vld.dll
像普通扩展一样加载这个扩展.调用vld的方法如下:
C:\Documents and Settings\Administrator.TEST1111&gt;php -dvld.active=1 d:\\1.php
Failed loading php_xdebug.dll
Branch analysis from position: 12647312
Return found
filename:       D:\1.php
function name:  (null)
number of ops:  4
compiled vars:  !0 = $a
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  ASSIGN                                                   !0, 1
   3     1  ECHO                                                     !0
   4     2  RETURN                                                   1
         3* ZEND_HANDLE_EXCEPTION

1</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2009/11/23</a>, qq347835460 writes: 补充一点,楼主的代码(svn: http://code.google.com/p/opcodesdumper/source/)在windows下面理论上是可以编译成exe的.但是windows下的php的Embed SAPI是不一样,windows下的php默认支持Embed SAPI,在二进制包的根目录下面有一个.
php5embed.lib到底干什么用的,情况不明.
楼主的代码编译的时候要在最前面加上以下两句,否则编译阶段就会出错.
#define ZEND_WIN32
#define PHP_WIN32
同样需要下载源码包,源码包里面才有sapi/embed/php_embed.h,同样需要设置vc的inlude目录,把php5embed.lib加到lib目录下后编译还是无法通过,链接的时候出错了,具体原因不清楚.如果编译成exe了,使用起来就更方便了...(^_^这只是一个构思,还没有成为事实.)</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2010/09/19</a>, <a href="http://www.yakecan.com/archives/460"  rel="external nofollow"  class="url" >(转)深入理解PHP原理之变量分离/引用(Variables Separation) &raquo; Creative Power</a> writes: [...] 使用PHP Embed SAPI实现Opcodes查看器 [...]</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=204"  rel="external nofollow"  class="url" >使用PHP Embed SAPI实现Opcodes查看器 | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/09/23/539.html [...]</li><li><a href="http://www.laruence.com/2008/09/23/539.html" >2012/01/01</a>, <a href="http://liangzhenjing@gmail.com"  rel="external nofollow"  class="url" >砖家</a> writes: 很通俗易懂。入门很好。

PS：这代码颜色配色不错，能分享一下吗</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2009/12/26/1198.html"  title="深入理解PHP原理之变量生命期(一)" >深入理解PHP原理之变量生命期(一)</a></li><li><a href="http://www.laruence.com/2008/11/07/581.html"  title="PHP的GET/POST等大变量生成过程" >PHP的GET/POST等大变量生成过程</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/09/23/539.html/feed</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>深入理解PHP原理之变量分离/引用(Variables Separation)</title>
		<link>http://www.laruence.com/2008/09/19/520.html</link>
		<comments>http://www.laruence.com/2008/09/19/520.html#comments</comments>
		<pubDate>Fri, 19 Sep 2008 07:47:19 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[change on write]]></category>
		<category><![CDATA[Copy on write]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[separation]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=520</guid>
		<description><![CDATA[<p>在前面的文章中我已经介绍了PHP的变量的内部表示(<a rel="bookmark" href="http://www.laruence.com/2008/08/22/412.html">深入理解PHP原理之变量(Variables inside PHP)</a>)，以及PHP中作用域的实现机制(<a rel="bookmark" href="http://www.laruence.com/2008/08/26/463.html">深入理解PHP原理之变量作用域(Scope inside PHP)</a>)。这节我们就接着前面的文章，继续介绍PHP中变量分离和引用的概念：</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/09/19/520.html"  title="Permanet Link to 深入理解PHP原理之变量分离/引用(Variables Separation)" >http://www.laruence.com/2008/09/19/520.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>在前面的文章中我已经介绍了PHP的变量的内部表示(<a rel="bookmark"  href="http://www.laruence.com/2008/08/22/412.html" >深入理解PHP原理之变量(Variables inside PHP)</a>)，以及PHP中作用域的实现机制(<a rel="bookmark"  href="http://www.laruence.com/2008/08/26/463.html" >深入理解PHP原理之变量作用域(Scope inside PHP)</a>)。这节我们就接着前面的文章，继续介绍PHP中变量分离和引用的概念：</p>
<p>首先我们回顾一下zval的结构：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
struct _zval_struct {
        /* Variable information */
        zvalue_value value;             /* value */
        zend_uint refcount;
        zend_uchar type;        /* active type */
        zend_uchar is_ref;
};
</pre>
<p>其中的refcount和is_ref字段我们一直都没有介绍过，我们知道PHP是一个长时间运行的服务器端的脚本解释器。那么对于它来说，效率和资源占用率是一个很重要的衡量标准，也就是说，PHP必须尽量介绍内存占用率，考虑下面这段代码：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
   $var = &quot;laruence&quot;;
   $var_dup = $var;
   unset($var);
?&gt;
</pre>
<p>第一行代码创建了一个字符串变量，申请了一个大小为9字节的内存，保存了字符串&#8221;laruence&#8221;和一个NULL(\0)的结尾。<br/>
第二行定义了一个新的字符串变量，并将变量var的值&#8221;复制&#8221;给这个新的变量。<br/>
第三行unset了变量var</p>
<p>这样的代码在我们平时的脚本中是很常见的，如果PHP对于每一个变量赋值都重新分配内存，copy数据的话，那么上面的这段代码公要申请18个字节的内存空间，而我们也很容易的看出来，上面的代码其实根本没有必要申请俩份空间，呵呵，PHP的开发者也看出来了：</p>
<p>我们之前讲过，PHP中的变量是用一个存储在symbol_table中的符号名，对应一个zval来实现的，比如对于上面的第一行代码，会在symbol_table中存储一个值&#8221;var&#8221;, 对应的有一个指针指向一个zval结构，变量值&#8221;laruence&#8221;保存在这个zval中，所以不难想象，对于上面的代码来说，我们完全可以让&#8221;var&#8221;和&#8221;var_dup&#8221;对应的指针都指向同一个zval就可以了。</p>
<p>PHP也是这样做的，这个时候就需要介绍我们之前一直没有介绍过的zval结构中的refcount字段了。<br/>
refcount,顾名思义，记录了当前的zval被引用的计数。<br/>
比如对于代码:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
   $var = 1;
   $var_dup = $var;
?&gt;
</pre>
<p>第一行，创建了一个整形变量，变量值是1。 此时保存整形1的这个zval的refcount为1。<br/>
第二行，创建了一个新的整形变量，变量也指向刚才创建的zval，并将这个zval的refcount加1，此时这个zval的refcount为2。<br/>
PHP提供了一个函数可以帮助我们了解这个过程debug_zval_dump:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
 $var = 1;
 debug_zval_dump($var);
 $var_dup = $var;
 debug_zval_dump($var);
?&gt;
</pre>
<p>输出：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
long(1) refcount(2)
long(1) refcount(3)
</pre>
<p>如果你奇怪 ，var的refcount应该是1啊？<br/>
我们知道，对于简单变量，PHP是以传值的形式穿参数的。也就是说，当执行debug_zval_dump($var)的时候，$var会以传值的方式传递给debug_zval_dump，也就是会导致var的refcount加1，所以我们只要能看到，当变量赋值给一个变量以后，能导致zval的refcount加1这个事实即可。</p>
<p>  现在我们回头看文章开头的代码， 当执行了最后一行unset($var)以后，会发生什么呢？ 对，既是refcount减1，上代码：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
   $var = &quot;laruence&quot;;
   $var_dup = $var;
   unset($var);
   debug_zval_dump($var_dup);
?&gt;
</pre>
<p>输出：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
string(8) &quot;laruence&quot; refcount(2)
</pre>
<p>但是，对于下面的代码呢？</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
   $var = &quot;laruence&quot;;
   $var_dup = $var;
   $var = 1;
?&gt;
</pre>
<p>  很明显在这段代码执行以后，$var_dup的值应该还是&#8221;laruence&#8221;, 那么这又是怎么实现的呢？<br/>
这就是PHP的copy on write机制：<br/>
  PHP在修改一个变量以前，会首先查看这个变量的refcount，如果refcount大于1，PHP就会执行一个分离的例程， 对于上面的代码，当执行到第三行的时候，PHP发现$var指向的zval的refcount大于1，那么PHP就会复制一个新的zval出来，将原zval的refcount减1，并修改symbol_table，使得$var和$var_dup分离(Separation)。这个机制就是所谓的copy on write(写时复制)。</p>
<p>上代码测试：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
   $var = &quot;laruence&quot;;
   $var_dup = $var;
   $var = 1;
   debug_zval_dump($var);
   debug_zval_dump($var_dup);
?&gt;
</pre>
<p>输出：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
long(1) refcount(2)
string(8) &quot;laruence&quot; refcount(2)
</pre>
<p>现在我们知道，当使用变量复制的时候 ，PHP内部并不是真正的复制，而是采用指向相同的结构来尽量节约开销。那么，对于PHP中的引用，那又是如何实现呢？</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
   $var = &quot;laruence&quot;;
   $var_ref = &amp;$var;
   $var_ref = 1;
?&gt;
</pre>
<p>这段代码结束以后，$var也会被间接的修改为1，这个过程称作(change on write:写时改变)。那么ZE是怎么知道，这次的复制是不需要Separation的呢？<br/>
这个时候就要用到zval中的is_ref字段了：<br/>
对于上面的代码，当第二行执行以后，$var所代表的zval的refcount变为2，并且同时置is_ref为1。<br/>
到第三行的时候，PHP先检查var_ref代表的zval的is_ref字段，如果为1，则不分离，大体逻辑示意如下：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
 if((*val)-&gt;is_ref || (*val)-&gt;refcount&lt;2){
		//不执行Separation
        ... ;//process
  }
</pre>
<p>但是，问题又来了，对于如下的代码，又会怎样呢？</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
   $var = &quot;laruence&quot;;
   $var_dup = $var;
   $var_ref = &amp;$var;
?&gt;
</pre>
<p>对于上面的代码，存在一对copy on write的变量$var和$var_dup, 又有一对change on write机制的变量对$var和$var_ref，这个情况又是如何运作的呢？</p>
<p>当第二行执行的时候，和前面讲过的一样，$var_dup 和 $var 指向相同的zval， refcount为2.<br/>
当执行第三行的时候，PHP发现要操作的zval的refcount大于1，则，PHP会执行Separation, 将$var_dup分离出去，并将$var和$var_ref做change on write关联。也就是，refcount=2, is_ref=1;</p>
<p>基于这样的分析，我们就可以让debug_zval_dump出refcount为1的结果来：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
	$var = &quot;laruence&quot;;
    $var_dup = &amp;$var;
	debug_zval_dump($var);
?&gt;
</pre>
<p>输出：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
string(8) &quot;laruence&quot; refcount(1)
</pre>
<p>详细原因，读者你只要稍加分析就能得出，我就不越俎代庖了。；）</p>
<p>这次我们介绍了PHP的变量分离机制，下次我会继续介绍如果在扩展中接收和传出PHP脚本中的参数。另外，因为最近变动比较大(换工作),所以抱歉这么长时间才有更新。</p>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/09/20</a>, snowrui writes: 写的很详细.</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/09/20</a>, snowrui writes: 前面:

当第二行执行的时候，和前面讲过的一样，$var_dup 和 $var 指向相同的zval， refcount为2.


最后:

输出：
string(8) "laruence" refcount(1)


可能是我没看明白,引用时引用计数不加吧.
我测试:
    $var = "laruence";
    $var_dup = &amp;$var;
    $var_dup1 = &amp;$var;
    $var_dup2 = &amp;$var;
    debug_zval_dump($var);
    $var_dup = 1;
    debug_zval_dump($var);
输出:
string(8) "laruence" refcount(1)
long(1) refcount(1)</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/09/20</a>, snowrui writes: 啊他把我复制你的代码给过滤了.晕</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/09/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 你这个时候，调用debug_zval_dump会导致一个Separation动作的产生， 所以会refcount 1
引用的时候，refcount是会增加的。</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/09/20</a>, snowrui writes: 奥.明白了.我忘了,那个函数的参数,多谢指教</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/09/20</a>, snowrui writes: $var = "laruence";
    $var_dup = &amp;$var;
    $var_dup1 = &amp;$var;
    $var_dup2 = &amp;$var;
    debug_zval_dump(&amp;$var);
输出:
&amp;string(8) "laruence" refcount(5)


只是输出时多了个&amp;号.不知道什么意思,可能表示是个引用.</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/09/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 恩, 这样的时候,就不会分离了.</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/10/09</a>, tianxj writes: 发现一个拼写错误 ：）
“PHP提供了一个函数可以帮助我们了解这个过程debug_dump_zval”中函数“debug_dump_zval”应为“debug_zval_dump”</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/10/10</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: ;), 谢谢, 改正之</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/10/25</a>, <a href="http://hi.baidu.com/jackywdx"  rel="external nofollow"  class="url" >jackywdx</a> writes: 呵呵，写的文章非常好，继续加油啊。</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/11/12</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >guoxiaod</a> writes: 刚才 想到 上次和同事讨论 关于 for 和 foreach 的问题， 

那们到底 foreach 有没有重新复制一份 value.
如果重新复制一份的话，从理论上讲 应该要比 for 花费多的时间。</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2008/11/14</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 它不是整个复制，foreach开始的时候, 在zend_do_foreach_count()中，只是复制数组的current元素，
所以，复制这部分的开销不是很大
相反，如果使用了for， 花费在索引查询上的时间，会差不多大于花在foreach上的元素复制时间。

所以，总体来说，不会差很多，但是建议使用foreach</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2009/02/09</a>, sky writes: 分离次序好像应该遵循FIFO原则把？</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2009/02/09</a>, sky writes: 现在的分离条件好象是
PZVAL_IS_REF(value) &amp;&amp; value-&gt;refcount &gt; 0

即is_ref=1并且refcount&gt;0的时候可以分离，
这样snowrui 提供的代码就可以解释输出的内容了
输出:
string(8) “laruence” refcount(1)
long(1) refcount(1)</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2009/05/27</a>, <a href="http://NULL"  rel="external nofollow"  class="url" >npc0der</a> writes: 

如果说第一个 debug_zval_dump 中传递 $val 导致 val 的refcount + 1  为什么第二次调用 不会加一呢?</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2009/05/27</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: <?php
    $var = "laruence"; //$var ref=1
    $var_dup = &$var; // $var ref=2 is_ref=1
    debug_zval_dump($var);//传值调用,change on wirte, 分离出参数$var
?></li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/01/03</a>, <a href="http://www.laruence.com/2010/01/03/1225.html"  rel="external nofollow"  class="url" >一个想当然造成的错误(赋值语句的返回值) | 风雪之隅</a> writes: [...] 结合之前的文章深入理解PHP原理之变量分离/引用(Variables Separation)中介绍过的相关知识, [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/05/18</a>, Anonymous writes: 

结果：
Array
(
  [0] =&gt; C
)

博主，能否结合PHP源码，帮忙分析下上面的代码，这个问题困扰我一段时间了，一直没能真正理解其中的原理。</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/05/18</a>, Anonymous writes: 前面提交的代码为啥没了。。再提交一次：

  $arr[0] = 'A'; $tmp = &amp; $arr[0];
  $foo = $arr;
  $arr[0] = 'C';
  print_r($foo);


结果：
Array
(
  [0] =&gt; C
)</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/05/18</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @Anonymous Hi, foo指向的是arr整体的zval, 而tmp是引用指向arr中hashtable的一个元素zval, 所以在对arr[0]赋值的时候,不会触发分离动作.</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/05/20</a>, Anonymous writes: 博主，非常感谢你的及时回复！那天晚上结合你的文章，钻研了很久，今天发现和你想到一块去了，哈哈。我在进一步测试时，又有了新发现：
对数组进行 &amp; 后，其数组元素的 refcount会加1，但是不知道数组元素的 isref 是否也会变成 1？因为 debug_zval_dump()看不到 isref，所以不知道还有没有其它函数可以看 isref的呢？还请告知！</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/05/20</a>, Anonymous writes: 另外，还有个问题：当$foo = $arr后，他们是指向同一ZVAL的，但什么情况下，他们会被分离呢？
我试着改变他们元素的值，对数组排序等操作，似乎都不能将他们分离。。</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/05/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >laruence</a> writes: Anonymous</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/05/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >laruence</a> writes: @Anonymous  最直接的方法是用gdb, 引用数组不会改变元素的refcount, 分离不是指引用的, 分离只是指多个符号指向同一个zval的情况, ;)</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/06/22</a>, <a href="http://www.laruence.com/2010/06/22/1618.html"  rel="external nofollow"  class="url" >ReflectionFunction(Method)引用参数导致Invocation failed | 风雪之隅</a> writes: [...] 也就是说, 如果一个申明为引用传递的参数的refcount大于1了, 并且不容许分离的话, 就会导致出错.(如果对refcount和变量分离不了解, 可以参看我之前的文章深入理解PHP原理之变量分离/引用(Variables Separation)) [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/07/04</a>, <a href="http://www.uh80.com/?p=592"  rel="external nofollow"  class="url" >ReflectionFunction(Method)引用参数导致Invocation failed &laquo; phplife</a> writes: [...] 也就是说, 如果一个申明为引用传递的参数不为引用传递, 而refcount又大于1, 那么在不容许分离的条件下, 就会导致zend_call_function失败返回(如果对refcount和变量分离不了解, 可以参看我之前的文章深入理解PHP原理之变量分离/引用). [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/07/26</a>, kevindoudou writes: 楼主真是大牛～～～～百度真是藏龙卧虎～～～～学习学习～～～</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2010/09/19</a>, <a href="http://www.yakecan.com/archives/460"  rel="external nofollow"  class="url" >(转)深入理解PHP原理之变量分离/引用(Variables Separation) &raquo; Creative Power</a> writes: [...] 本文地址: http://www.laruence.com/2008/09/19/520.html [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/02/16</a>, fengchuan writes: 楼主我对你十分敬仰啊。。。。大牛</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/03/04</a>, <a href="http://www.laruence.com/2011/03/04/1894.html"  rel="external nofollow"  class="url" >谁动了我的内存(PHP内存管理) | 风雪之隅</a> writes: [...] 还要结合引用和计数, 这部分的内容请参看我之前的文章深入理解PHP原理之变量分离/引用), 但这个释放不是C编程意义上的释放, 不是交回给OS. 对于PHP来说, [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/03/18</a>, <a href="http://www.laruence.com/2011/03/18/1916.html"  rel="external nofollow"  class="url" >可序列化单例模式的一个奇怪问题的回答 | 风雪之隅</a> writes: [...] var_dump($a === Singleton::getInstance()); //bool(false)  那么为什么呢? 我之前的文章深入理解PHP原理之变量分离/引用(Variables Separation)中曾经介绍过, 在PHP中, [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=272"  rel="external nofollow"  class="url" >一个想当然造成的错误(赋值语句的返回值) | 万维网黑客联盟</a> writes: [...] 结合之前的文章深入理解PHP原理之变量分离/引用(Variables Separation)中介绍过的相关知识, [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=286"  rel="external nofollow"  class="url" >深入理解PHP原理之变量分离/引用(Variables Separation) | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/09/19/520.html [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/08/22</a>, 晓彬 writes: 最后一题，将$var和$var_ref做change on write关联。也就是，refcount=2, is_ref=1;
为什么 dump 出来 引用计数是1呢？而且还有一个形参的1，就代表原先他本是的引用计数是0吗？</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/08/22</a>, 晓彬 writes: 我也试着去gdb了。
按照说的 声明变量的时候。
要写到符号表中，ZEND_SET_SYMBOL
我就gdb php
break ZEND_SET_SYMBOL
run test.php
断点貌似没用到就结束了。
Php部分是
$var = 1;
$var_ref = &amp;$var;
困惑。
还有，最后一题的 引用计数为啥是1呢？
在赋值的时候$var的zval里的refcount=1 is_ref=0, 应该是不用分离的啊。
难道在$var_ref = &amp;$var; 这次赋值以后才进行的 分离么？困惑求解。</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/09/14</a>, <a href="http://warpigallen.sinaapp.com/?p=63"  rel="external nofollow"  class="url" >warpig&#039;s blog &raquo; 深入理解PHP内存管理之谁动了我的内存</a> writes: [...] 还要结合引用和计数, 这部分的内容请参看我之前的文章深入理解PHP原理之变量分离/引用), 但这个释放不是C编程意义上的释放, 不是交回给OS. 对于PHP来说, [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/11/04</a>, <a href="http://www.laruence.com/2011/11/04/2258.html"  rel="external nofollow"  class="url" >三元式(ternary)性能优化 | 风雪之隅</a> writes: [...] 我们都知道PHP用写时复制来对变量复制做性能优化, 而在以前的三元式中, 却每次都会复制, 这在操作数是大数组的情况下, 会造成性能问题: [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/12/20</a>, <a href="http://weizhao.me/?p=2055"  rel="external nofollow"  class="url" >php的copy on write和change on write一点想法 | Weizhao</a> writes: [...] http://www.laruence.com/2008/09/19/520.html?cp=all [...]</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2011/12/20</a>, Anonymous writes: “PHP必须尽量介绍内存占用率” 是否应为 “PHP必须尽量减少内存占用率”</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2012/01/25</a>, <a href="http://cc.ecjtu.net"  rel="external nofollow"  class="url" >Cyrec</a> writes: 鸟哥写的很详细，受益匪浅。</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2012/01/28</a>, yufulou writes: 最后一题和前面说得根本自相矛盾吧？前面也有一个一样的，您在那的说法是refcount=2,is_ref=1才是啊</li><li><a href="http://www.laruence.com/2008/09/19/520.html" >2012/01/28</a>, yufulou writes: 看了鸟哥前面的回复，知道怎么回事了，还得感叹一句，原来是鸟哥！！！久仰大名</li></ul><hr/><h2>Related posts:</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2009/07/27/1020.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之错误抑制与内嵌HTML" >深入理解PHP原理之错误抑制与内嵌HTML</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2011/03/29/1949.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之Session Gc的一个小概率Notice" >深入理解PHP原理之Session Gc的一个小概率Notice</a></li><li><a href="http://www.laruence.com/2010/06/20/1602.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP之匿名函数" >深入理解PHP之匿名函数</a></li><li><a href="http://www.laruence.com/2010/05/04/1450.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP之require/include顺序" >深入理解PHP之require/include顺序</a></li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li><li><a href="http://www.laruence.com/2007/12/16/308.html"  title="PHP:Header" >PHP:Header</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/09/19/520.html/feed</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>深入理解PHP原理之变量作用域(Scope in PHP)</title>
		<link>http://www.laruence.com/2008/08/26/463.html</link>
		<comments>http://www.laruence.com/2008/08/26/463.html#comments</comments>
		<pubDate>Tue, 26 Aug 2008 10:03:21 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=463</guid>
		<description><![CDATA[<p>我前面的文章介绍了PHP变量的内部表示，但是，问题是，这些内部表示是如何和用户脚本中的变量联系起来的呢？也就是说，如果我在脚本中写下：
<coolcode lang="php" linenum="off">
<?php
  $var = "laruence";
  echo $var;
?>
</coolcode>
ZE是如何把我的变量var和内部结构zval联系起来的呢？</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/26/463.html"  title="Permanet Link to 深入理解PHP原理之变量作用域(Scope in PHP)" >http://www.laruence.com/2008/08/26/463.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>我前面的文章(<a href="http://www.laruence.com/2008/08/22/412.html" >深入理解PHP原理之变量(Variables inside PHP)</a>)介绍了PHP变量的内部表示，但是，问题是，这些内部表示是如何和用户脚本中的变量联系起来的呢？也就是说，如果我在脚本中写下：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
  $var = &quot;laruence&quot;;
  echo $var;
?&gt;
</pre>
<p>ZE是如何把我的变量var和内部结构zval联系起来的呢？</p>
<p>深入理解PHP原理之变量中讲过，PHP内部都是使用zval来表示变量的，但是对于上面的脚本，我们的变量是有名字的, var。而zval中并没有相应的字段来体现变量名。<br/>
 如果你想到了PHP内部一定有一个机制，来实现变量名到zval的映射。那么你真的是很聪明，；）</p>
<p> 在PHP中，所有的变量都会存储在一个数组中(确切的说是hash table), 并且，PHP也是通过不同的数组来实现变量的作用域的。</p>
<p> 当你创建一个变量的时候，PHP会为这个变量分配一个zval，填入相应的变量值，然后将这个变量的名字，和指向这个zval的指针填入一个数组中。然后，当你获取这个变量的时候，PHP会通过查找这个数组，获得对应的zval。</p>
<p> 查看_zend_executor_globals结构(这个结构在PHP的执行器保存一些执行相关的上下文信息)</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
struct _zend_executor_globals {

	....
    HashTable *active_symbol_table;/*活动符号表*/
    HashTable symbol_table;     /*全局符号表*/

    HashTable included_files;   

    jmp_buf *bailout;
    int error_reporting;
	.....
}
 </pre>
<p>  其中，全局符号表，保存了在顶层作用域(就是不在任何函数，对象内)的变量。每当调用一个函数(对象的方法)的时候，就会为这个函数创建一个活动符号表，所有在这个函数内定义的变量，都会保存在这个活动符号表中。</p>
<p>  对,这就是PHP的变量作用域的实现方式! 举个列子：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
  &lt;?php
	$var = &quot;I am in the global symbol table&quot;;
    function sample($para){
        $var = &quot;I am in the active symbol table&quot;;
		echo $var;
 	}
    sample($var);
    echo $var;
  ?&gt;
</pre>
<p>  在函数sample外面的变量$var,它会被填入全局符号表中，与他对应的有一个zval指针，这个zval保存了一个字符串&#8221;I am in the global symbol table&#8221;.<br/>
  函数内的$var, 它会被填入属于函数sample的活动符号表中，一样的，与他对应的zval中，保存着字符串&#8221;I am in the active symbol table<br/>
&#8220;.<br/>
  比较特殊的，就是函数sample的参数$para了，这个$para是保存在sample的活动符号表的，但是与他对应的zval指针，会指向一个保存一份全局变量$var的copy的zval(严格来讲不是copy，是引用，这个涉及到变量的copy on write机制，我会在以后介绍)。</p>
<p>  我们都知道PHP对于简单变量是传值调用的，但是，我要告诉你的是，PHP并不是简单的通过复制一个zval来实现传值的，呵呵，留个悬念，等我下回分解. </p>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/26/463.html" >2008/08/30</a>, 爱上 writes: 咋不分解了啦</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2008/08/31</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 呵呵，不好意思啊，最近项目很紧，等忙过这阵，我一次多写点。</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2008/09/11</a>, xiaoj writes: 楼主后面是不是准备讲refererce,copy on write,change on write了</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2008/09/11</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 恩, 是应该介绍这方面的东西了</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2009/02/09</a>, sky writes: 既然symbol_table和*active_symbol_table都是HashTable结构，那变量名是放在哪呢，好像不知道symbol_table结构中哪个元素作为存放变量名和值用，即key/value</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2009/07/16</a>, <a href="http://www.53uni.cn"  rel="external nofollow"  class="url" >游泳减肥</a> writes: 路过，顺便顶下</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2010/09/19</a>, <a href="http://www.yakecan.com/archives/460"  rel="external nofollow"  class="url" >(转)深入理解PHP原理之变量分离/引用(Variables Separation) &raquo; Creative Power</a> writes: [...] 在前面的文章中我已经介绍了PHP的变量的内部表示(深入理解PHP原理之变量(Variables inside PHP))，以及PHP中作用域的实现机制(深入理解PHP原理之变量作用域(Scope inside PHP))。这节我们就接着前面的文章，继续介绍PHP中变量分离和引用的概念： [...]</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2010/12/08</a>, <a href="http://www.laruence.com/2010/12/08/1716.html"  rel="external nofollow"  class="url" >如何获取一个变量的名字 | 风雪之隅</a> writes: [...] 关于作用域, 你也可以参看我之前的文章: 深入理解PHP原理之变量作用域(Scope in PHP) [...]</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=241"  rel="external nofollow"  class="url" >深入理解PHP原理之变量作用域(Scope in PHP) | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/26/463.html [...]</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2011/06/23</a>, <a href="http://www.laruence.com/2011/06/23/2057.html"  rel="external nofollow"  class="url" >如何调试PHP的Core(一) | 风雪之隅</a> writes: [...] 在这个过程中, 会涉及到对PHP的函数调用, PHP的传参, PHP的一些全局变量的知识, 这些知识在我之前的文章中都有过涉及, 大家可以翻阅: 深入理解PHP原理之函数 深入理解PHP原理之变量作用域等等. [...]</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2011/07/04</a>, <a href="http://xiesiqi.com/php5-4%e7%9a%84%e6%96%b0%e7%89%b9%e6%80%a7/"  rel="external nofollow"  class="url" >PHP5.4的新特性 &mdash; 见贤思齐</a> writes: [...] 深入理解PHP原理之变量作用域(Scope in PHP) [...]</li><li><a href="http://www.laruence.com/2008/08/26/463.html" >2011/09/19</a>, <a href="http://blog.csdn.net/lgg201"  rel="external nofollow"  class="url" >selfimpr</a> writes: 我们都知道PHP对于简单变量是传值调用的，但是，我要告诉你的是，PHP并不是简单的通过复制一个zval来实现传值的，呵呵，留个悬念，等我下回分解. 

请问, 这个指的是"copy-on-write"还是有其他的知识??</li></ul><hr/><h2>Related posts:</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2009/07/27/1020.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之错误抑制与内嵌HTML" >深入理解PHP原理之错误抑制与内嵌HTML</a></li><li><a href="http://www.laruence.com/2011/03/29/1949.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之Session Gc的一个小概率Notice" >深入理解PHP原理之Session Gc的一个小概率Notice</a></li><li><a href="http://www.laruence.com/2010/06/20/1602.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP之匿名函数" >深入理解PHP之匿名函数</a></li><li><a href="http://www.laruence.com/2010/05/04/1450.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP之require/include顺序" >深入理解PHP之require/include顺序</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li><li><a href="http://www.laruence.com/2007/12/16/308.html"  title="PHP:Header" >PHP:Header</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/26/463.html/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>深入理解PHP原理之变量(Variables inside PHP)</title>
		<link>http://www.laruence.com/2008/08/22/412.html</link>
		<comments>http://www.laruence.com/2008/08/22/412.html#comments</comments>
		<pubDate>Fri, 22 Aug 2008 14:36:18 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[variable]]></category>
		<category><![CDATA[Zend/PHP]]></category>
		<category><![CDATA[zval]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=412</guid>
		<description><![CDATA[<p>或许你知道，或许你不知道，PHP是一个弱类型，动态的脚本语言。所谓弱类型，就是说PHP并不严格验证变量类型(严格来讲，PHP是一个中强类型语言,这部分内容会在以后的文章中叙述)，在申明一个变量的时候，并不需要显示指明它保存的数据的类型。而PHP的核心ZE是用C编写的，大家都知道C是一个强类型语言，也就是说，在C中所有的变量在它被声明到最终销毁，都只能保存一种类型的数据。 那么PHP是如何在ZE的基础上实现弱类型的呢？且听我慢慢道来....</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/22/412.html"  title="Permanet Link to 深入理解PHP原理之变量(Variables inside PHP)" >http://www.laruence.com/2008/08/22/412.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>或许你知道，或许你不知道，PHP是一个弱类型，动态的脚本语言。所谓弱类型，就是说PHP并不严格验证变量类型(严格来讲，PHP是一个中强类型语言,这部分内容会在以后的文章中叙述)，在申明一个变量的时候，并不需要显示指明它保存的数据的类型：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
  $var = 1; //int
  $var = &quot;laruence&quot;; //string
  $var = 1.0002; //float
  $var = array(); // array
  $var = new Exception('error'); //object;
</pre>
<p>  动态语言，就是说，PHP的语言结构在运行期是可以改变的，比如我们在运行期require一个函数定义文件，从而导致语言的函数表动态的改变。<br/>
  所谓脚本语言，就是说，PHP并不是独立运行的，要运行PHP我们需要PHP解析器：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
  /usr/bin/php -f example.php
</pre>
<p>   我前面的文章中已经讲过，PHP的执行是通过Zend engine(ZE, Zend引擎), ZE是用C编写的，大家都知道C是一个强类型语言，也就是说，在C中所有的变量在它被声明到最终销毁，都只能保存一种类型的数据。 那么PHP是如何在ZE的基础上实现弱类型的呢？</p>
<div style="color:blue;padding-lef" >首先要声明一点，如果你以前没有接触过PHP的源码分析，扩展开发。 如果你并不了解PHP的架构， 没有听说ZE，那么我建议你先看看我前面的文章,尤其推荐：</p>
<li><a href="http://www.laruence.com/2008/08/11/147.html" >深入浅出PHP(PHP Internals)</a></li>
<li><a href="http://www.laruence.com/2008/06/18/221.html" >深入理解PHP原理之Opcodes</a></li>
</div>
<p>   在PHP中，所有的变量都是用一个结构-zval来保存的， 在Zend/zend.h中我们可以看到zval的定义：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
  typedef struct _zval_struct {
    zvalue_value value;
    zend_uint refcount;
    zend_uchar type;
    zend_uchar is_ref;
  } zval;
 </pre>
<p>    其中zvalue_value是真正保存数据的关键部分，现在到了揭晓谜底的时候了，PHP是如何在ZE的基础上实现弱类型的呢？ 因为zvalue_value是个联合体(union), </p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
typedef union _zvalue_value {
    long lval;
    double dval;
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;
    zend_object_value obj;
} zvalue_value;
</pre>
<p>   那么这个结构是如何储存PHP中的多种类型的呢？<br/>
   PHP中常见的变量类型有：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. 整型/浮点/长整型/bool值 等等
2. 字符串
3. 数组/关联数组
4. 对象
5. 资源
  </pre>
<p>   PHP根据zval中的type字段来储存一个变量的真正类型，然后根据type来选择如何获取zvalue_value的值，比如对于整型和bool值:</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
   zval.type = IS_LONG;//整形
   zval.type = IS_BOOL;//布尔值
</pre>
<p>   就去取zval.value.lval,对于bool值来说lval∈(0|1);<br/>
   如果是双精度，或者float则会去取zval.value的dval。<br/>
   而如果是字符串，那么:</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
   zval.type = IS_STRING
</pre>
<p>   这个时候，就会取:<br/>
    zval.value.str<br/>
   而这个也是个结构，存有C分格的字符串和字符串的长度。</p>
<p>   而对于数组和对象，则type分别对应IS_ARRAY, IS_OBJECT, 相对应的则分别取zval.value.ht和obj</p>
<p>   比较特别的是资源，在PHP中，资源是个很特别的变量，任何不属于PHP内建的变量类型的变量，都会被看作成资源来进行保存，比如，数据库句柄，打开的文件句柄等等。 对于资源:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
   type = IS_RESOURCE
</pre>
<p>   这个时候，会去取zval.value.lval， 此时的lval是个整型的指示器， 然后PHP会再根据这个指示器在PHP内建的一个资源列表中查询相对应的资源(这部分的内容，我以后会单独开一个篇文章来介绍)，目前，你只要知道此时的lval就好像是对应于资源链表的偏移值。</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
 ZEND_FETCH_RESOURCE(con, type, zval *, default, resource_name, resource_type);
</pre>
<p>    借用这样的机制，PHP就实现了弱类型，因为对于ZE的来说，它所面对的永远都是同一种类型，那就是zval。<br/>
    ps:明天team出去building，我想着应该在走之前写点东西给我的blog reader来消磨周末。今天就简单先开个头，下一次，我将进一步介绍PHP的变量，作用域，以及变量的copy on write和change on write机制， 待续&#8230;.<br/>
  <script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/22/412.html" >2008/08/23</a>, 左手 writes: 太佩服你了，强大的很</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2008/08/26</a>, <a href="http://fy"  rel="external nofollow"  class="url" >fj</a> writes: mark</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2008/08/27</a>, bush writes: 在PHP中，所有的变量都是用一个结构-zval来保存的， 在Zend/zend.h中我们可以看到zval的定义：

在php应用中 Zend相关的文件没有找到或见过  它属于哪一部分呢</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2008/08/27</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 我指的Zend/zend.h是相当于PHP源码结构树的根目录
比如,我看的是PHP5.2,那么Zend就是
PHP5.2-SRC/Zend/</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2008/09/23</a>, 狂笨地太阳 writes: 太好了，终于理解PHP的变量是怎么个样子了。。PHP变量类型不同，ZVAL的TYPE就不同。</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2008/11/25</a>, <a href="http://www.benleo.cn/?p=186"  rel="external nofollow"  class="url" >完全COPY : 深入理解PHP原理之变量分离/引用(Variables Separation)</a> writes: [...] Separation) 在前面的文章中我已经介绍了PHP的变量的内部表示(深入理解PHP原理之变量(Variables inside PHP))，以及PHP中作用域的实现机制(深入理解PHP原理之变量作用域(Scope inside [...]</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2008/11/26</a>, yzcj007 writes: 感谢搂主，写得很棒，加油写，等着看呢！</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2010/03/25</a>, Anonymous writes: 牛人</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2010/05/18</a>, <a href="http://www.laruence.com/2010/05/18/1482.html"  rel="external nofollow"  class="url" >深入理解PHP原理之对象(一) | 风雪之隅</a> writes: [...] 对象的结构 在PHP5中, 一个对象, 还是以一个zval做为载体的, 还记得什么是Zval么(深入理解PHP原理之变量). [...]</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2010/05/26</a>, <a href="http://crazyphper.com/wblog/archives/777"  rel="external nofollow"  class="url" >深入理解 PHP之require/include顺序 &laquo; 大熊猫 &#8211; konakona ——PHP程序员</a> writes: [...] 在PHP5中, 一个对象, 还是以一个zval做为载体的, 还记得什么是Zval么(深入理解 PHP原理之变量). [...]</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2010/07/30</a>, <a href="http://zhidao.123doing.com/32792.html"  rel="external nofollow"  class="url" >关于引用的一个小问题。。。散分。。 - PHP常见问题 - 关于引用 一个小问题 散分 PHP 基础编程 - 123Doing</a> writes: [...] unset只是将$t指向的zval结构体的refcount &#8211; 1,然后清除符号表里的&#8217;t&#39;,去除$t与zval的关联但是$s仍然是关联zval的。我说不明白，有一篇高手写的文章专门讲这个的，在本坛我贴出来不少次了，你认真看看。http://www.laruence.com/2008/08/22/412.html [...]</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2010/09/19</a>, <a href="http://www.yakecan.com/archives/460"  rel="external nofollow"  class="url" >(转)深入理解PHP原理之变量分离/引用(Variables Separation) &raquo; Creative Power</a> writes: [...] 在前面的文章中我已经介绍了PHP的变量的内部表示(深入理解PHP原理之变量(Variables inside PHP))，以及PHP中作用域的实现机制(深入理解PHP原理之变量作用域(Scope inside PHP))。这节我们就接着前面的文章，继续介绍PHP中变量分离和引用的概念： [...]</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2011/01/31</a>, <a href="http://zhidao.123doing.com/52141.html"  rel="external nofollow"  class="url" >关于引用的一个小问题。。。散分。。 - PHP常见问题 - [标签:tags] - 开源网 | 123Doing</a> writes: [...] 如果你在php4和php5中分别执行上述代码，则php4 得到 21php5 得到 22  unset只是将$t指向的zval结构体的refcount &#8211; 1,然后清除符号表里的&#8217;t&#039;,去除$t与zval的关联但是$s仍然是关联zval的。我说不明白，有一篇高手写的文章专门讲这个的，在本坛我贴出来不少次了，你认真看看。http://www.laruence.com/2008/08/22/412.html 关键是这篇http://www.laruence.com/2008/09/19/520.html然后再结合php的GC原理会更深入一些。http://www.php.net/manual/en/features.gc.refcounting-basics.php [...]</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2011/03/18</a>, <a href="http://51nosql.com"  rel="external nofollow"  class="url" >51nosql</a> writes: 向大牛学习，关注</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2011/03/20</a>, <a href="http://www.iirr.info/blog/?p=155"  rel="external nofollow"  class="url" >HorseLuke@微碌 &raquo; Blog Archive &raquo; php缓存扩展频繁存储/读取数组引发CPU过高问题排查手记（php-memcache为例）</a> writes: [...] [2]laruence. 深入理解PHP原理之变量(Variables inside PHP)：http://www.laruence.com/2008/08/22/412.html [...]</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2011/03/23</a>, liano writes: 牛人啊，我现在在学php能否给我个联系地址请教你一下啊？
qq：584418561</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2011/08/23</a>, Forever writes: 照这样说每个变量占用的内存都比较大，因为它是结构体类型啊。结构体占用的内存不是所有类型加起来的嘛</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2011/08/23</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @Forever 不是结构体, 是union ;)</li><li><a href="http://www.laruence.com/2008/08/22/412.html" >2011/09/02</a>, <a href="http://warpigallen.sinaapp.com/?p=13"  rel="external nofollow"  class="url" >深入理解PHP原理之变量(Variables inside PHP) | warpig_allen&#039;s blog</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/22/412.html [...]</li></ul><hr/><h2>Related posts:</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/26/463.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2009/06/01/905.html"  rel="bookmark"  title="Permanent Link: 开心网偷菜外挂" >开心网偷菜外挂</a></li><li><a href="http://www.laruence.com/2009/07/27/1020.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之错误抑制与内嵌HTML" >深入理解PHP原理之错误抑制与内嵌HTML</a></li><li><a href="http://www.laruence.com/2011/03/29/1949.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之Session Gc的一个小概率Notice" >深入理解PHP原理之Session Gc的一个小概率Notice</a></li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2009/12/26/1198.html"  title="深入理解PHP原理之变量生命期(一)" >深入理解PHP原理之变量生命期(一)</a></li><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/22/412.html/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>PHP 源代码分析 V0.0.2</title>
		<link>http://www.laruence.com/2008/08/15/274.html</link>
		<comments>http://www.laruence.com/2008/08/15/274.html#comments</comments>
		<pubDate>Fri, 15 Aug 2008 02:56:13 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP Extension]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=274</guid>
		<description><![CDATA[做为我以后乱写的一个指导方针。呵呵
  PHP 源代码分析目录

   1. 第一章 构建系统 准备工具、库及需要具备的基础知识；
   2. 如何编译不同平台的版本？编译时的各个选项是什么含义？
   3. 如何创建一个 PHP 扩展/模块？如何创建一个 Zend 扩展？
   4. 如何调试 PHP？如何调试 PHP/Zend 扩展？

   1. 第二章 PHP 与 SAPI 的生命周期 脚本的运行周期
   2. 模块/脚本的起始与终止函数； ...]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/15/274.html"  title="Permanet Link to PHP 源代码分析 V0.0.2" >http://www.laruence.com/2008/08/15/274.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>  做为我以后乱写的一个指导方针。呵呵</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
   PHP 源代码分析目录

   1. 第一章 构建系统 准备工具、库及需要具备的基础知识；
   2. 如何编译不同平台的版本？编译时的各个选项是什么含义？
   3. 如何创建一个 PHP 扩展/模块？如何创建一个 Zend 扩展？
   4. 如何调试 PHP？如何调试 PHP/Zend 扩展？

   1. 第二章 PHP 与 SAPI 的生命周期 脚本的运行周期
   2. 模块/脚本的起始与终止函数；
   3. PHP SAPI 协议；
   4. 嵌入式 PHP 设计。

   1. 第三章 内存管理 Zend 的内存管理器框架；
   2. 内存申请与释放流程，垃圾回收；
   3. 持久化（persistence）

   1. 第四章 线程安全 TSRM
   2. 我是否该启用 ZTS？各有什么优缺点？
   3. 如何构建一个 ZTS 的程序/扩展？

   1. 第五章 变量与常量 PHP 中的数据类型。
   2. 变量、常量与静态变量。
   3. 引用计数机制；
   4. 资源的创建与回收；
   5. 未来字符串的 UNICODE 支持、JIT 支持。

   1. 第六章 函数 函数的内部布局；
   2. 函数的定义；
   3. 如何获取函数的参数。可选参数、参数默认值；
   4. 函数的返回值；

   1. 第七章 类与对象 类的内部布局（属性、方法）；
   2. 构造函数与析构函数；
   3. 类的继承与转换；
   4. 接口（轻量级的类），微观上与类的差别；
   5. 类之间的up casting 和 down casting。
   6. stdClass。

   1. 第八章 错误与异常 什么是错误、什么是异常。两者的区别；
   2. 如何创建和抛出异常；
   3. try/catch 的设计与实现；

   1. 第九章 流（Streams）支持 这方面我接触较少，内容待定；

   1. 第十章 虚拟机 脚本编译机制（词法分析、语法分析）；
   2. 脚本的执行机制（CALL|SWITCH|GOTO）；
   3. 各个符号表的作用；
   4. 开发 OPCode 缓存器；
   5. 开发 PHP 调试器；
   6. PHP编译执行分离的实现(或者，源码加密的实现)

   1. 附录 完整的 PHP API、Zend API 以及宏（Micro）参考（长期工程）
   2. Zend Engine 1 的主要特性，与 Zend Engine 2的主要差别；
   3. Zend Engine 3 的主要特性，与 Zend Engine 2的主要差别；
   4. 相关资源
</pre>
<p>这个目录是抚琴居主人写好的，我打算和他合作写这个东西，所以再这个之上做了一些调整，曰v0.02, <img src="http://www.laruence.com/wp-includes/images/smilies/icon_smile.gif"  alt=":)"  class="wp-smiley" /> <script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/15/274.html" >2008/08/23</a>, liexusong writes: 支持！！什么时候完成啊？？</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2008/08/24</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 目前还只是在不断充实中，现在写的blog，有一部分就是为这个服务的。</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2008/09/09</a>, babby writes: 国内php的源码分析很少啊
加油！</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2008/09/19</a>, <a href="http://www.aibang.com"  rel="external nofollow"  class="url" >apple</a> writes: 这本书明年可以完成吗？</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2008/09/19</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 恩，我们在努力。。呵呵。；）</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2008/10/06</a>, <a href="http://www.thinkalab.com"  rel="external nofollow"  class="url" >东方云</a> writes: 你真的才25岁吗？你真厉害！你对php这么精通，我可以有空请教你吗，只要指点一下就可以的，哈哈~~</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2008/10/06</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 呵呵，其实也是有点名过其实，还是在学习的过程中。；）</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2008/12/12</a>, laotan writes: 有预览的吗？真想快点看见</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2009/12/21</a>, pestd writes: 路过，加油！</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2010/03/02</a>, <a href="http://t.sina.com.cn/liruqi"  rel="external nofollow"  class="url" >liruqi</a> writes: 我觉得，基础数据类型的实现也可以写一些...</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2010/07/19</a>, <a href="http://www.bpzc.net/"  rel="external nofollow"  class="url" >bpzc</a> writes: 可以提供一下工具吗？
谢谢</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2010/07/29</a>, <a href="http://www.g.cn"  rel="external nofollow"  class="url" >google</a> writes: 楼主写到哪一步了</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2010/09/06</a>, Anonymous writes: 什么时候写这个呀，好久没有消息了，期待啊</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2010/09/19</a>, <a href="http://www.yakecan.com/archives/460"  rel="external nofollow"  class="url" >(转)深入理解PHP原理之变量分离/引用(Variables Separation) &raquo; Creative Power</a> writes: [...] PHP 源代码分析 V0.0.2 [...]</li><li><a href="http://www.laruence.com/2008/08/15/274.html" >2010/12/22</a>, toknow writes: 请问什么时候正式出书呀？</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li><li><a href="http://www.laruence.com/2007/12/16/308.html"  title="PHP:Header" >PHP:Header</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/15/274.html/feed</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>实现PHP的编译执行分离(separating compilation and execution)</title>
		<link>http://www.laruence.com/2008/08/14/250.html</link>
		<comments>http://www.laruence.com/2008/08/14/250.html#comments</comments>
		<pubDate>Wed, 13 Aug 2008 16:08:27 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP Extension]]></category>
		<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=250</guid>
		<description><![CDATA[   刚刚在PHP群内和大家聊天，应承了大家要写一个关于如何实现PHP源码加密的文章， 借着这会QA在冒烟的机会，就这个问题，我写点思路....]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/14/250.html"  title="Permanet Link to 实现PHP的编译执行分离(separating compilation and execution)" >http://www.laruence.com/2008/08/14/250.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>   刚刚在PHP群内和大家聊天，应承了大家要写一个关于如何实现PHP源码加密的文章， 借着这会QA在冒烟的机会，就这个问题，我写点思路。<br/>
   我之前的文章介绍过， ZE（Zend engine) 执行一个PHP脚本会经历编译－>执行， 只不过它每次执行都会去重新编译PHP文件。并没有实现编译和执行分离。<br/>
   在ZE的编译和执行阶段，有俩个重要的函数:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
</pre>
<p>   和</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
  ZEND_API void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
  </pre>
<p>  zend_compile_file负责将要执行的脚本文件编译成由ZE的基本指令序列构成的op codes , 然后将op codes交由zend_execute执行，从而得到我们脚本的结果。</p>
<p>  所以，我们完全可以通过修改默认的zend_complie_file和zend_execute来实现，PHP的执行和编译分离，进一步，我们还可以再这个基础上实现，对我们脚本的加密和解密。</p>
<p>  我们通过一个PHP扩展模块来实现这个功能， 首先，我们需要在模块初始化的时候:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
 PHP_MINIT_FUNCTION(sample)
{
    old_compile_file = zend_compile_file;  //保存现场
    old_execute = zend_execute;

    zend_compile_file = my_compile_file; //截获
    zend_execute = my_execute;
    return SUCCESS;
}
</pre>
<p> 在我们的my_compile_file中，判断我们的文件是否是编译过的文件，假设后缀名是 *.ze</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
    static zend_op_array *my_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
{
    if(strstr(file_handle-&gt;filename, &quot;.ze&quot;) != NULL){//是编译过的文件。
         直接返回文件内容.
    }
   zend_op_array *op_array;

   op_array = old_compile_file (file_handle, type TSRMLS_CC); //调用默认的compile,截获输出

   if(op_array){
       保存op_array;
   }
    return op_array;
}
</pre>
<p>这样，我们就实现了， 对已经编译文件的支持，和对文件编译的支持。<br/>
然后，需要编写我们的执行函数:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
static void my_execute(zend_op_array *op_array TSRMLS_DC)
{
    old_execute(op_array TSRMLS_DC); //简单交由默认执行函数执行。
}
</pre>
<p>也许你要问为什么要包装以后的执行函数， 呵呵，我只是为了说明，一种方式，就是可以截获这个东东而已。。 有什么用，就看读者你有什么要求能通过这个方式实现了 ；）</p>
<p>恩，写到这里， 你也许就明白了， 如果想要对文件加密， 那么就定义个加密文件类型，比如 *.zec， 然后在my_compile_file中，判断文件类型，如果是加密文件，那么就执行解密，；），嘿嘿，简答吧？</p>
<p>至于怎么加密，，，那就要问你自己了，你想用什么方式，，，但是，记住，要可逆的哦～～ ^_^。<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/14/250.html" >2008/08/16</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >guoxiaod</a> writes: 为什么要为 中国的开源事业制造绊脚石呢？</li><li><a href="http://www.laruence.com/2008/08/14/250.html" >2008/08/16</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 呵呵，人各有志么，我只是说个实现方式。。 
我是坚实的开源拥护者。</li><li><a href="http://www.laruence.com/2008/08/14/250.html" >2008/08/20</a>, Leric writes: 估计APC之类的opcode缓存就是这么实现的吧，也不知道那些缓存的东西都放哪儿了</li><li><a href="http://www.laruence.com/2008/08/14/250.html" >2008/08/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 恩对，APC的实现原理和这个差不多，一般来说会存在内存,或者类dbm的数据库中。</li><li><a href="http://www.laruence.com/2008/08/14/250.html" >2009/05/12</a>, Anonymous writes: 最近研究這方面，在源代碼級別上開發有很多方面可以應用。</li><li><a href="http://www.laruence.com/2008/08/14/250.html" >2009/09/11</a>, phper writes: 不加密怎么样保存op_array？怎么直接返回文件内容？
zend_op_array好像是链表类的结构体.
您有没有测试过?有实例代码吗?

if(op_array){
       保存op_array;
   }

if(strstr(file_handle-&gt;filename, ".ze") != NULL){//是编译过的文件。
         直接返回文件内容.
    }</li><li><a href="http://www.laruence.com/2008/08/14/250.html" >2009/09/11</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @phper 惭愧, 我没有测试过,只是谈个想法, 呵呵.  这块要实现,  还是要做很大实验的.</li><li><a href="http://www.laruence.com/2008/08/14/250.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=248"  rel="external nofollow"  class="url" >实现PHP的编译执行分离(separating compilation and execution) | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/14/250.html [...]</li></ul><hr/><h2>Related posts:</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2011/12/06/2381.html"  rel="bookmark"  title="Permanent Link: 更简单的重现PHP Core的调用栈" >更简单的重现PHP Core的调用栈</a></li><li><a href="http://www.laruence.com/2009/07/19/1003.html"  rel="bookmark"  title="Permanent Link: 使用gettext来支持PHP的多语言" >使用gettext来支持PHP的多语言</a></li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li><li><a href="http://www.laruence.com/2007/12/16/308.html"  title="PHP:Header" >PHP:Header</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/14/250.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>深入理解Zend SAPIs(Zend SAPI Internals)</title>
		<link>http://www.laruence.com/2008/08/12/180.html</link>
		<comments>http://www.laruence.com/2008/08/12/180.html#comments</comments>
		<pubDate>Tue, 12 Aug 2008 10:35:38 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP Extension]]></category>
		<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[Extension]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SAPI]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=180</guid>
		<description><![CDATA[SAPI: Server abstraction API，研究过PHP架构的同学应该知道这个东东的重要性，它提供了一个接口，使得PHP可以和其他应用进行交互数据。 本文不会详细介绍PHP的每个SAPI，只是针对最简单的CGI SAPI，来说明SAPI的机制...]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/12/180.html"  title="Permanet Link to 深入理解Zend SAPIs(Zend SAPI Internals)" >http://www.laruence.com/2008/08/12/180.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>SAPI: Server abstraction API，研究过PHP架构的同学应该知道这个东东的重要性，它提供了一个接口，使得PHP可以和其他应用进行交互数据。 本文不会详细介绍每个PHP的SAPI，只是针对最简单的CGI SAPI，来说明SAPI的机制。</p>
<p>首先，我们来看看PHP的架构图：<br/>
<center><div id="attachment_181"  class="wp-caption alignnone"  style="width: 303px" ><a href="http://laruence-wordpress.stor.sinaapp.com/uploads/php-arch.jpg" ><img src="http://laruence-wordpress.stor.sinaapp.com/uploads/php-arch-293x300.jpg"  alt="PHP架构图"  title="php-arch"  width="293"  height="300"  class="size-medium wp-image-181" /></a><p class="wp-caption-text" >PHP架构图</p></div></center><br/>
<center>图1 PHP Architecture</center><br/>
 SAPI提供了一个和外部通信的接口， 对于PHP5.2，默认提供了很多种SAPI， 常见的给apache的mod_php5，CGI，给IIS的ISAPI，还有Shell的CLI，本文就从CGI SAPI入手 ，介绍SAPI的机制。 虽然CGI简单，但是不用担心，它包含了绝大部分内容，足以让你深刻理解SAPI的工作原理。</p>
<p>要定义个SAPI，首先要定义个sapi_module_struct,  查看 PHP-SRC/sapi/cgi/cgi_main.c:</p>
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
 */
static sapi_module_struct cgi_sapi_module = {
#if PHP_FASTCGI
    &quot;cgi-fcgi&quot;,                     /* name */
    &quot;CGI/FastCGI&quot;,                  /* pretty name */
#else
    &quot;cgi&quot;,                          /* name */
    &quot;CGI&quot;,                          /* pretty name */
#endif

    php_cgi_startup,                /* startup */
    php_module_shutdown_wrapper,    /* shutdown */

    NULL,                           /* activate */
    sapi_cgi_deactivate,            /* deactivate */

    sapi_cgibin_ub_write,           /* unbuffered write */
    sapi_cgibin_flush,              /* flush */
    NULL,                           /* get uid */
    sapi_cgibin_getenv,             /* getenv */

    php_error,                      /* error handler */

    NULL,                           /* header handler */
    sapi_cgi_send_headers,          /* send headers handler */
    NULL,                           /* send header handler */

    sapi_cgi_read_post,             /* read POST data */
    sapi_cgi_read_cookies,          /* read Cookies */

    sapi_cgi_register_variables,    /* register server variables */
    sapi_cgi_log_message,           /* Log message */
    NULL,                           /* Get request time */

    STANDARD_SAPI_MODULE_PROPERTIES
};
</pre>
<p>    这个结构，包含了一些常量，比如name, 这个会在我们调用php_info()的时候被使用。一些初始化，收尾函数，以及一些函数指针，用来告诉Zend，如何获取，和输出数据。</p>
<li>1. php_cgi_startup， 当一个应用要调用PHP的时候，这个函数会被调用，对于CGI来说，它只是简单的调用了PHP的初始化函数：
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
   static int php_cgi_startup(sapi_module_struct *sapi_module)
{
    if (php_module_startup(sapi_module, NULL, 0) == FAILURE) {
        return FAILURE;
    }
    return SUCCESS;
}
   </pre>
</li>
<li>2. php_module_shutdown_wrapper ， 一个对PHP关闭函数的简单包装。只是简单的调用php_module_shutdown;</li>
<li>3. PHP会在每个request的时候，处理一些初始化，资源分配的事务。这部分就是activate字段要定义的，从上面的结构我们可以看出，对于CGI来说，它并没有提供初始化处理句柄。对于mod_php来说，那就不同了，他要在apache的pool中注册资源析构函数， 申请空间， 初始化环境变量，等等等等。</li>
<li>4. sapi_cgi_deactivate, 这个是对应与activate的函数，顾名思义，它会提供一个handler, 用来处理收尾工作，对于CGI来说，他只是简单的刷新缓冲区，用以保证用户在Zend关闭前得到所有的输出数据：
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
  static int sapi_cgi_deactivate(TSRMLS_D)
{
    /* flush only when SAPI was started. The reasons are:
        1. SAPI Deactivate is called from two places: module init and request shutdown
        2. When the first call occurs and the request is not set up, flush fails on
            FastCGI.
    */
    if (SG(sapi_started)) {
        sapi_cgibin_flush(SG(server_context));
    }
    return SUCCESS;
}</pre>
</li>
<li>5. sapi_cgibin_ub_write, 这个hanlder告诉了Zend，如何输出数据，对于mod_php来说，这个函数提供了一个向response数据写的接口，而对于CGI来说，只是简单的写到stdout：
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">

static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
{
#ifdef PHP_WRITE_STDOUT
    long ret;
#else
    size_t ret;
#endif

#if PHP_FASTCGI
    if (fcgi_is_fastcgi()) {
        fcgi_request *request = (fcgi_request*) SG(server_context);
        long ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
        if (ret &lt;= 0) {
            return 0;
        }
        return ret;
    }
#endif
#ifdef PHP_WRITE_STDOUT
    ret = write(STDOUT_FILENO, str, str_length);
    if (ret &lt;= 0) return 0;
    return ret;
#else
    ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
    return ret;
#endif
}

static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
{
    const char *ptr = str;
    uint remaining = str_length;
    size_t ret;

    while (remaining &gt; 0) {
        ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
        if (!ret) {
            php_handle_aborted_connection();
            return str_length - remaining;
        }
        ptr += ret;
        remaining -= ret;
    }

    return str_length;
}
</pre>
<p>把真正的写的逻辑剥离出来，就是为了简单实现兼容fastcgi的写方式。
 </li>
<li>6. sapi_cgibin_flush, 这个是提供给zend的刷新缓存的函数句柄，对于CGI来说，只是简单的调用系统提供的fflush;</li>
<li>7.NULL， 这部分用来让Zend可以验证一个要执行脚本文件的state，从而判断文件是否据有执行权限等等，CGI没有提供。</li>
<li>8. sapi_cgibin_getenv, 为Zend提供了一个根据name来查找环境变量的接口，对于mod_php5来说，当我们在脚本中调用getenv的时候，就会间接的调用这个句柄。而对于CGI来说，因为他的运行机制和CLI很类似，直接调用父级是Shell， 所以，只是简单的调用了系统提供的genenv:
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
{
#if PHP_FASTCGI
    /* when php is started by mod_fastcgi, no regular environment
       is provided to PHP.  It is always sent to PHP at the start
       of a request.  So we have to do our own lookup to get env
       vars.  This could probably be faster somehow.  */
    if (fcgi_is_fastcgi()) {
        fcgi_request *request = (fcgi_request*) SG(server_context);
        return fcgi_getenv(request, name, name_len);
    }
#endif
    /*  if cgi, or fastcgi and not found in fcgi env
        check the regular environment */
    return getenv(name);
}
</pre>
</li>
<li> 9. php_error, 错误处理函数, 到这里，说几句题外话，上次看到php maillist 提到的使得PHP的错误处理机制完全OO化， 也就是，改写这个函数句柄，使得每当有错误发生的时候，都throw一个异常。而CGI只是简单的调用了PHP提供的错误处理函数。</li>
<li>10. 这个函数会在我们调用PHP的header()函数的时候被调用，对于CGI来说，不提供。</li>
<li>11. sapi_cgi_send_headers,  这个函数会在要真正发送header的时候被调用，一般来说，就是当有任何的输出要发送之前：
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
{
    char buf[SAPI_CGI_MAX_HEADER_LENGTH];
    sapi_header_struct *h;
    zend_llist_position pos;

    if (SG(request_info).no_headers == 1) {
        return  SAPI_HEADER_SENT_SUCCESSFULLY;
    }

    if (cgi_nph || SG(sapi_headers).http_response_code != 200)
    {
        int len;

        if (rfc2616_headers &amp;&amp; SG(sapi_headers).http_status_line) {
            len = snprintf(buf, SAPI_CGI_MAX_HEADER_LENGTH,
                           &quot;%s\r\n&quot;, SG(sapi_headers).http_status_line);

            if (len &gt; SAPI_CGI_MAX_HEADER_LENGTH) {
                len = SAPI_CGI_MAX_HEADER_LENGTH;
            }

        } else {
            len = sprintf(buf, &quot;Status: %d\r\n&quot;, SG(sapi_headers).http_response_code);
        }

        PHPWRITE_H(buf, len);
    }

    h = (sapi_header_struct*)zend_llist_get_first_ex(&amp;sapi_headers-&gt;headers, &amp;pos);
    while (h) {
        /* prevent CRLFCRLF */
        if (h-&gt;header_len) {
            PHPWRITE_H(h-&gt;header, h-&gt;header_len);
            PHPWRITE_H(&quot;\r\n&quot;, 2);
        }
        h = (sapi_header_struct*)zend_llist_get_next_ex(&amp;sapi_headers-&gt;headers, &amp;pos);
    }
    PHPWRITE_H(&quot;\r\n&quot;, 2);

    return SAPI_HEADER_SENT_SUCCESSFULLY;
   }
  </pre>
</li>
<li> 12. NULL, 这个用来单独发送每一个header, CGI没有提供</li>
<li> 13. sapi_cgi_read_post, 这个句柄指明了如何获取POST的数据，如果做过CGI编程的话，我们就知道CGI是从stdin中读取POST DATA的，
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
{
    uint read_bytes=0, tmp_read_bytes;
#if PHP_FASTCGI
    char *pos = buffer;
#endif

    count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
    while (read_bytes &lt; count_bytes) {
#if PHP_FASTCGI
        if (fcgi_is_fastcgi()) {
            fcgi_request *request = (fcgi_request*) SG(server_context);
            tmp_read_bytes = fcgi_read(request, pos, count_bytes - read_bytes);
            pos += tmp_read_bytes;
        } else {
            tmp_read_bytes = read(0, buffer + read_bytes, count_bytes - read_bytes);
        }
#else
        tmp_read_bytes = read(0, buffer + read_bytes, count_bytes - read_bytes);
#endif

        if (tmp_read_bytes &lt;= 0) {
            break;
        }
        read_bytes += tmp_read_bytes;
    }
    return read_bytes;
}
</pre>
</li>
<li> 14. sapi_cgi_read_cookies, 这个和上面的函数一样，只不过是去获取cookie值：
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">static char *sapi_cgi_read_cookies(TSRMLS_D)
{
    return sapi_cgibin_getenv((char *) &quot;HTTP_COOKIE&quot;, sizeof(&quot;HTTP_COOKIE&quot;)-1 TSRMLS_CC);
}
</pre>
</li>
<li> 15. sapi_cgi_register_variables, 这个函数给了一个接口，用以给$_SERVER变量中添加变量，对于CGI来说，注册了一个PHP_SELF,这样我们就可以在脚本中访问$_SERVER['PHP_SELF']来获取本次的request_uri：
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
{
    /* In CGI mode, we consider the environment to be a part of the server
     * variables
     */
    php_import_environment_variables(track_vars_array TSRMLS_CC);
    /* Build the special-case PHP_SELF variable for the CGI version */
    php_register_variable(&quot;PHP_SELF&quot;, (SG(request_info).request_uri ? SG(request_info).request_uri : &quot;&quot;), track_vars_array TSRMLS_CC);
}
</pre>
</li>
<li> 16. sapi_cgi_log_message ，用来输出错误信息，对于CGI来说，只是简单的输出到stderr:
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">static void sapi_cgi_log_message(char *message)
{
#if PHP_FASTCGI
    if (fcgi_is_fastcgi() &amp;&amp; fcgi_logging) {
        fcgi_request *request;
        TSRMLS_FETCH();

        request = (fcgi_request*) SG(server_context);
        if (request) {
            int len = strlen(message);
            char *buf = malloc(len+2);

            memcpy(buf, message, len);
            memcpy(buf + len, &quot;\n&quot;, sizeof(&quot;\n&quot;));
            fcgi_write(request, FCGI_STDERR, buf, len+1);
            free(buf);
        } else {
            fprintf(stderr, &quot;%s\n&quot;, message);
        }
        /* ignore return code */
    } else
#endif /* PHP_FASTCGI */
    fprintf(stderr, &quot;%s\n&quot;, message);
}
</pre>
</li>
<p>经过分析，我们已经了解了一个SAPI是如何实现的了， 分析过CGI以后，我们也就可以想象mod_php, embed等SAPI的实现机制。 ：）</p>
<p>今天就到这里， 西班牙和中国加时了，呵呵，中国男篮还不错。。。。。。<br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/08/12</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 唉，中国男篮还是输了。。。真不能夸。</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/08/13</a>, yongtao.pang writes: 不错，清晰的很。
占个沙发慢慢看。</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/09/15</a>, snowrui writes: 很细,先慢慢看先</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/09/24</a>, <a href="http://fy"  rel="external nofollow"  class="url" >fj</a> writes: 能告诉我你那张图从哪里来的吗？</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/09/24</a>, <a href="http://fy"  rel="external nofollow"  class="url" >fj</a> writes: 如果是一本书，那本书名是什么呢？</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/09/24</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 恩，是从Sams《Advanced PHP Programming》中截的。</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/09/24</a>, <a href="http://fy"  rel="external nofollow"  class="url" >fj</a> writes: 3q:)</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/09/24</a>, <a href="http://faryang.cn"  rel="external nofollow"  class="url" >fj</a> writes: 这本书放在我电脑上一年以上,,深刻反省！</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2008/11/25</a>, <a href="http://www.benleo.cn/?p=178"  rel="external nofollow"  class="url" >完全COPY : 使用PHP Embed SAPI实现Opcodes查看器</a> writes: [...] 如果你对PHP的SAPI还不熟悉的话，我建议你看看我的这篇文章：深入理解Zend SAPIs(Zend SAPI Internals) 这个时候，你就可以在你的C代码中，嵌入PHP脚本解析器了， 我的例子：  #include &#8220;sapi/embed/php_embed.h&#8220;   int main(int argc, char * argv[]){     PHP_EMBED_START_BLOCK(argc,argv);     char * script = &#8220; print &#8216;Hello World!&#8217;;&#8220;;     zend_eval_string(script, NULL,                                       &#8220;Simple Hello World App&#8220; TSRMLS_CC);     PHP_EMBED_END_BLOCK();     return 0; } [...]</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2010/09/20</a>, Cirilo writes: Would you like to <a href="http://www.jerseysusa.com"  rel="nofollow" >Wholesale Jerseys </a>.
Establish relationship with jerseysusa for <a href="http://www.jerseysusa.com"  rel="nofollow" >Wholesale Jerseys </a> .</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=215"  rel="external nofollow"  class="url" >深入理解Zend SAPIs(Zend SAPI Internals) | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/12/180.html [...]</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2011/09/16</a>, <a href="http://unknownerror.net/2011-07/67098-php-bottom-working-principle.html"  rel="external nofollow"  class="url" >PHP bottom working principle</a> writes: [...] Rain bloghttp://www.laruence.com/2008/08/12/180.html [...]</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2011/09/16</a>, <a href="http://warpigallen.sinaapp.com/?p=160"  rel="external nofollow"  class="url" >warpig&#039;s blog &raquo; 深入理解Zend SAPIs(Zend SAPI Internals)</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/12/180.html [...]</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2011/11/25</a>, <a href="http://blog.168sun.com/?p=41"  rel="external nofollow"  class="url" >lamp 工作原理</a> writes: [...] 风雨的博客http://www.laruence.com/2008/08/12/180.html [...]</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2011/12/05</a>, <a href="http://www.8ou.cn/20111205/php-id-2/"  rel="external nofollow"  class="url" >PHP底层工作原理 - 木林森的博客</a> writes: [...] 风雨的博客http://www.laruence.com/2008/08/12/180.html [...]</li><li><a href="http://www.laruence.com/2008/08/12/180.html" >2011/12/24</a>, <a href="http://www.php10086.com/2011/12/php%e5%ba%95%e5%b1%82%e5%b7%a5%e4%bd%9c%e5%8e%9f%e7%90%86/"  rel="external nofollow"  class="url" >PHP底层工作原理 | PHP10086博客网</a> writes: [...] 风雨的博客http://www.laruence.com/2008/08/12/180.html [...]</li></ul><hr/><h2>Related posts:</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/15/274.html"  rel="bookmark"  title="Permanent Link: PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/07/16/225.html"  rel="bookmark"  title="Permanent Link: Zend Engine幻想" >Zend Engine幻想</a></li><li><a href="http://www.laruence.com/2008/09/23/539.html"  rel="bookmark"  title="Permanent Link: 使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2010/06/21/1608.html"  rel="bookmark"  title="Permanent Link: PHP调试技术手册发布(1.0.0 pdf)" >PHP调试技术手册发布(1.0.0 pdf)</a></li><li><a href="http://www.laruence.com/2011/11/18/2305.html"  rel="bookmark"  title="Permanent Link: GBK编码PHP脚本导致语法错误(Zend Multibyte)" >GBK编码PHP脚本导致语法错误(Zend Multibyte)</a></li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2009/12/26/1198.html"  title="深入理解PHP原理之变量生命期(一)" >深入理解PHP原理之变量生命期(一)</a></li><li><a href="http://www.laruence.com/2009/08/18/1042.html"  title="保证PHP扩展的依赖关系" >保证PHP扩展的依赖关系</a></li><li><a href="http://www.laruence.com/2008/11/07/581.html"  title="PHP的GET/POST等大变量生成过程" >PHP的GET/POST等大变量生成过程</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/16/301.html"  title="扩展PHP[Extending PHP](一)" >扩展PHP[Extending PHP](一)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/12/180.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>深入理解PHP原理之函数(Introspecting PHP Function)</title>
		<link>http://www.laruence.com/2008/08/12/164.html</link>
		<comments>http://www.laruence.com/2008/08/12/164.html#comments</comments>
		<pubDate>Tue, 12 Aug 2008 04:03:07 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=164</guid>
		<description><![CDATA[在PHP中，函数分为俩种，
	<li>一种是zend_internal_function, 这种函数是由扩展或者Zend/PHP内核提供的，用'C/C++'编写的，可以直接执行的函数。</li>
        <li>另外一种是zend_user_function, 这种函数呢，就是我们经常在见的，用户在PHP脚本中定义的函数，这种函数最终会被ZE翻译成opcode array来执行</li>
      本文介绍了这俩中函数在ZE层面的不同点]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/12/164.html"  title="Permanet Link to 深入理解PHP原理之函数(Introspecting PHP Function)" >http://www.laruence.com/2008/08/12/164.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>在PHP中，函数分为俩种，</p>
<li>一种是zend_internal_function, 这种函数是由扩展或者Zend/PHP内核提供的，用&#8217;C/C++&#8217;编写的，可以直接执行的函数。</li>
<li>另外一种是zend_user_function, 这种函数呢，就是我们经常在见的，用户在PHP脚本中定义的函数，这种函数最终会被ZE翻译成opcode array来执行</li>
<p> 查看zend_compile.h,我们可以找到如下的3个结构:</p>
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
typedef struct _zend_internal_function {
    /* Common elements */
    zend_uchar type;
    char * function_name;
    zend_class_entry *scope;
    zend_uint fn_flags;
    union _zend_function *prototype;
    zend_uint num_args;
    zend_uint required_num_args;
    zend_arg_info *arg_info;
    zend_bool pass_rest_by_reference;
    unsigned char return_reference;
    /* END of common elements */

    void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
    struct _zend_module_entry *module;
} zend_internal_function;

struct _zend_op_array {
    /* Common elements */
    zend_uchar type;
    char *function_name;
    zend_class_entry *scope;
    zend_uint fn_flags;
    union _zend_function *prototype;
    zend_uint num_args;
    zend_uint required_num_args;
    zend_arg_info *arg_info;
    zend_bool pass_rest_by_reference;
    unsigned char return_reference;
    /* END of common elements */

    zend_uint *refcount;

    zend_op *opcodes;
    zend_uint last, size;

    zend_compiled_variable *vars;
    int last_var, size_var;

    zend_uint T;

    zend_brk_cont_element *brk_cont_array;
    zend_uint last_brk_cont;
    zend_uint current_brk_cont;

    zend_try_catch_element *try_catch_array;
    int last_try_catch;

    /* static variables support */
    HashTable *static_variables;

    zend_op *start_op;
    int backpatch_count;

    zend_bool done_pass_two;
    zend_bool uses_this;

    char *filename;

     zend_uint line_start;
    zend_uint line_end;
    char *doc_comment;
    zend_uint doc_comment_len;

    void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

typedef union _zend_function {
    zend_uchar type;    /* MUST be the first element of this struct! */

    struct {
        zend_uchar type;  /* never used */
        char *function_name;
        zend_class_entry *scope;
        zend_uint fn_flags;
        union _zend_function *prototype;
        zend_uint num_args;
        zend_uint required_num_args;
        zend_arg_info *arg_info;
        zend_bool pass_rest_by_reference;
        unsigned char return_reference;
    } common;

    zend_op_array op_array;
    zend_internal_function internal_function;
} zend_function;
    </pre>
<p> 第一个结构，定义了zend_internal_function, 当PHP启动的时候 ，它会遍历每个载入的扩展模块，然后将模块中function_entry中指明的每一个函数， 创建一个zend_internal_function结构， 并将type置为ZEND_INTERNAL_FUNCTION(见下表), 将这个结构填入全局的函数表(一个HashTable);</p>
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
#define ZEND_INTERNAL_FUNCTION              1
#define ZEND_USER_FUNCTION                  2
#define ZEND_OVERLOADED_FUNCTION            3
#define ZEND_EVAL_CODE                      4
#define ZEND_OVERLOADED_FUNCTION_TEMPORARY  5
      </pre>
<p>第二个结构，op_array, 这个结构很重要， 因为：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
      extern ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
   </pre>
<p>    也就是说，我们编写的PHP脚本，都会被ZE翻译成op_array,  最后交由zend_execute执行。
   </p>
<p>另外，在ZE中，用户定义的函数(userland function), 也会被翻译成一个op_array, 并填入全局函数表中。这个时候scope,function_name都不为空。而对于在全局作用域的直接代码来说，最后的op_array的scope为全局，function_name为空。</p>
<p>第三个结构， 很有趣， 要理解这个结构，首先你要理解他的设计目标： zend_internal_function, zend_function,zend_op_array可以安全的互相转换(The are not identical structs, but all the elements that are in &#8220;common&#8221; they hold in common, thus the can safely be casted to each other);</p>
<p>具体来说，当在op code中通过ZEND_DO_FCALL调用一个函数的时候，ZE会在函数表中，根据名字（其实是lowercase的函数名字，这也就是为什么PHP的函数名是大小写不敏感的)查找函数， 如果找到，返回一个zend_function结构的指针(仔细看这个上面的zend_function结构), 然后判断type,如果是ZEND_INTERNAL_FUNCTION， 那么ZE就调用zend_execute_internal,通过zend_internal_function.handler来执行这个函数， 如果不是，就调用zend_execute来执行这个函数包含的zend_op_array.</p>
<p>    <script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/12/164.html" >2008/08/12</a>, sue writes: 留言：Brett Anderson很帅</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2008/08/12</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: ....., 相关度为0的留言</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2008/08/13</a>, yongtao.pang writes: 学习了，期待下一篇</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2008/08/19</a>, Ande Lang writes: em... chinese?</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2009/05/14</a>, <a href="http://royaldrugstore.info/product/heart-shield.html"  rel="external nofollow"  class="url" >IntingeMeatty</a> writes: <a href="http://loveepicentre.com/"  rel="nofollow" >Love Epicentre</a> is one of the most popular online dating sites, and has a huge member database with thousands of free profiles to browse. It is a trusted and safe online dating site that caters to long term relationship seekers and finds your match based on personality traits.</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2010/05/18</a>, <a href="http://www.laruence.com/2010/05/18/1482.html"  rel="external nofollow"  class="url" >深入理解PHP原理之对象(一) | 风雪之隅</a> writes: [...] 这个函数表的结构和普通的函数表一样(深入理解PHP之函数), 也是以zend_op_array为最终载体, 所以和普通函数一样, [...]</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2010/05/25</a>, <a href="http://www.uh80.com/?p=495"  rel="external nofollow"  class="url" >深入理解PHP原理之对象(一) &laquo; phplife</a> writes: [...] 这个函数表的结构和普通的函数表一样(深入理解PHP之函数), 也是以zend_op_array为最终载体, 所以和普通函数一样, [...]</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2010/05/26</a>, <a href="http://crazyphper.com/wblog/archives/777"  rel="external nofollow"  class="url" >深入理解 PHP之require/include顺序 &laquo; 大熊猫 &#8211; konakona ——PHP程序员</a> writes: [...] 这个函数表的结构和普通的函数表一样(深入理解 PHP之函数), 也是以zend_op_array为最终载体, 所以和普通函数一样, [...]</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2010/06/09</a>, <a href="http://www.lowest-rate-loans.com"  rel="external nofollow"  class="url" >ClarkeJUANA35</a> writes: If you are willing to buy a house, you would have to receive the <a href="http://lowest-rate-loans.com"  rel="nofollow" >loans</a>. Furthermore, my brother always takes a term loan, which is really firm.</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2010/07/04</a>, <a href="http://www.sexynightwear.co.cc/"  rel="external nofollow"  class="url" >sexy nightwear</a> writes: 这个函数表的结构和普通的函数表一样(深入理解 PHP之函数), 也是以zend_op_array为最终载体, 所以和普通函数一样</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=212"  rel="external nofollow"  class="url" >深入理解PHP原理之函数(Introspecting PHP Function) | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/12/164.html [...]</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2011/03/22</a>, <a href="http://www.laruence.com/2011/03/22/1929.html"  rel="external nofollow"  class="url" >PHP Reflection Extension的一个bug | 风雪之隅</a> writes: [...] 而我们都知道, PHP的function_table中的函数都是小写的(参看我之前的文章深入理解PHP原理之函数(Introspecting PHP Function)). 于是reflection extension的如下这段代码就会报错: if (module-&gt;functions &amp;&amp; [...]</li><li><a href="http://www.laruence.com/2008/08/12/164.html" >2011/06/23</a>, <a href="http://www.laruence.com/2011/06/23/2057.html"  rel="external nofollow"  class="url" >如何调试PHP的Core(一) | 风雪之隅</a> writes: [...] 这些知识在我之前的文章中都有过涉及, 大家可以翻阅: 深入理解PHP原理之函数 [...]</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li><li><a href="http://www.laruence.com/2007/12/16/308.html"  title="PHP:Header" >PHP:Header</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/12/164.html/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>深入浅出PHP(Exploring PHP)</title>
		<link>http://www.laruence.com/2008/08/11/147.html</link>
		<comments>http://www.laruence.com/2008/08/11/147.html#comments</comments>
		<pubDate>Mon, 11 Aug 2008 12:48:43 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[Linux/Unix]]></category>
		<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[engine]]></category>
		<category><![CDATA[Internals]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=147</guid>
		<description><![CDATA[横观国内的PHP现状，一直以来，很少有专门介绍PHP内部机制的书。
对于Zend引擎，PHP扩展开发等相关的知识，中文资料很少。
呵呵，鉴于此：
我会随时记录下研究的心得，希望有机会的时候，可以汇总成书。:)]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/11/147.html"  title="Permanet Link to 深入浅出PHP(Exploring PHP)" >http://www.laruence.com/2008/08/11/147.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>一直以来，横观国内的PHP现状，很少有专门介绍PHP内部机制的书。呵呵，我会随时记录下研究的心得，有机会的时候，汇总成书。:)</p>
<p>今天这篇，我内心是想打算做为一个导论：</p>
<p>PHP是一个被广泛应用的脚本语言，因为它的成功，所以很多时候，我们应用PHP的时候是更不不需要考虑底层到底是怎么实现的。我相信大多数的PHP程序 员是不会去考虑这一点的。从我接触PHP开始，到今天也就是3年，这三年里，前俩年我一直都是在&#8221;用&#8221;PHP，每次写出来一段脚本，我就会想“恩，不用担 心，PHP解释器会知道我想做什么的”，直到去年来到雅虎，接受了一个工作，是做一个PHP的Extension，从这个时候开始，我就好奇于新接触的一 大堆的新鲜事物，zend, TSRM, zval, hashtable, op_array…</p>
<p>于是我到处查阅资料，每次获得一篇好的文章，或者一段好的文字我就会如获珍宝，打印保存起来，细细研读。我发现，国内关于PHP内部的资料真是少的可怜， 不知道是因为懂得的人多但是不愿意分享，还是懂得的人本来就少，所以，这条路，我走的很辛苦。于是，就会有了这篇文章。</p>
<p>在这篇文章中，我会从整个PHP的执行期入手，大致的介绍下各个阶段，词法分析，语法分析，op code等等，以后的文章我会再详细介绍每个阶(当然，如果你急不可耐的想知道详细，呵呵，那么可以直接联系我)。</p>
<p>从最初我们编写的PHP脚本-&gt;到最后脚本被执行-&gt;得到执行结果，这个过程，其实可以分为如下几个阶段（鄙视：CSDN不能上图）：</p>
<p>首先，Zend Engine(ZE)，调用词法分析器(Lex生成的，源文件在 Zend/zend_language_sanner.l), 将我们要执行的PHP源文件，去掉空格 ，注释，分割成一个一个的token。</p>
<p>然后，ZE会将得到的token forward给语法分析器(yacc生成, 源文件在 Zend/zend_language_parser.y)，生成一个一个的op code，opcode一般会以op array的形式存在，它是PHP执行的中间语言。</p>
<p>最后，ZE调用zend_executor来执行op array，输出结果。<br/>
   <center><a href="http://laruence-wordpress.stor.sinaapp.com/uploads/zend_engine.png" ><img src="http://laruence-wordpress.stor.sinaapp.com/uploads/zend_engine-300x276.png"  alt=""  title="zend_engine"  width="300"  height="276"  class="alignnone size-medium wp-image-154" /></a></center><br/>
                                      <center>图1 处理流程</center><br/>
ZE是一个虚拟机，正是由于它的存在，所以才能使得我们写PHP脚本，完全不需要考虑所在的操作系统类型是什么。ZE是一个CISC（复杂指令处理器）， 它支持150条指令（具体指令在 Zend/zend_vm_opcodes.h），包括从最简单的ZEND_ECHO(echo)到复杂的 ZEND_INCLUDE_OR_EVAL(include,require)，所有我们编写的PHP都会最终被处理为这150条指令(op code)的序列，从而最终被执行。</p>
<p>那有什么办法可以看到我们的PHP脚本，最终被“翻译”成什么样的呢？ 也就是说，op code张的什么样子呢？ 呵呵，达到这个，我们需要重新编译PHP，修改它的compile_file和zend_execute函数。不过，在PECL中已经有这样的模块，可以 让我们直接使用了，那就是由 Derick Rethans开发的VLD (Vulcan Logic Dissassembler)模块。你只要下载这个模块，并把他载入PHP中，就可以通过简单的设置，来得到脚本翻译的结果了。具体关于这个模块的使用说 明－雅虎一下，你就知道^_^。</p>
<p>接下来，让我们尝试用VLD来查看一段简单的PHP脚本的中间语言。</p>
<p>原始代码：</p>
<div class="hl-surround" >
<div class="hl-main" ><span style="color: blue;" >&lt;?php</span><span style="color: gray;" ></p>
<p></span><span style="color: #00008b;" >$i</span><span style="color: gray;" > = </span><span style="color: #8b0000;" >&#8220;</span><span style="color: red;" >This is a string</span><span style="color: #8b0000;" >&#8220;</span><span style="color: gray;" >;</p>
<p></span><span style="color: #ffa500;" >//I am comments</span><span style="color: gray;" ></p>
<p></span><span style="color: green;" >echo</span><span style="color: gray;" > </span><span style="color: #00008b;" >$i</span><span style="color: gray;" >.</span><span style="color: #8b0000;" >‘</span><span style="color: red;" > that has been echoed to screen</span><span style="color: #8b0000;" >‘</span><span style="color: gray;" >;</p>
<p></span><span style="color: blue;" >?&gt;</span></div>
</div>
<p>采用VLD得到的op codes:</p>
<div class="hl-surround" >
<div class="hl-main" ><span style="color: blue;" > filename</span><span style="color: gray;" >:/</span><span style="color: blue;" >home</span><span style="color: gray;" >/</span><span style="color: blue;" >Desktop</span><span style="color: gray;" >/</span><span style="color: blue;" >vldOutOne</span><span style="color: gray;" >.</span><span style="color: blue;" >php</span><span style="color: gray;" ></p>
<p></span><span style="font-family: Courier New;" ><span style="color: gray;" > </span><span style="color: green;" >function</span><span style="color: gray;" > </span><span style="color: blue;" >name</span><span style="color: gray;" >: </span><span style="color: olive;" >(</span><span style="color: green;" >null</span><span style="color: olive;" >)</span><span style="color: gray;" ></p>
<p></span><span style="color: blue;" >number</span><span style="color: gray;" > </span><span style="color: blue;" >of</span><span style="color: gray;" > </span><span style="color: blue;" >ops</span><span style="color: gray;" >: </span><span style="color: maroon;" >7</span><span style="color: gray;" ></p>
<p></span><span style="color: blue;" >line</span><span style="color: gray;" > </span><span style="color: #ffa500;" >#  op                 fetch       ext  operands</span><span style="color: gray;" ></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p></span><span style="color: maroon;" >2</span><span style="color: gray;" > </span><span style="color: maroon;" >0</span><span style="color: gray;" > </span><span style="color: blue;" >FETCH_W</span><span style="color: gray;" > </span><span style="color: blue;" >local</span><span style="color: gray;" > $</span><span style="color: maroon;" >0</span><span style="color: gray;" >, </span><span style="color: #8b0000;" >&#8216;</span><span style="color: red;" >i</span><span style="color: #8b0000;" >&#8216;</span><span style="color: gray;" ></p>
<p></span><span style="color: maroon;" >1</span><span style="color: gray;" > </span><span style="color: blue;" >ASSIGN</span><span style="color: gray;" > $</span><span style="color: maroon;" >0</span><span style="color: gray;" >, </span><span style="color: #8b0000;" >&#8216;</span><span style="color: red;" >This+is+a+string</span><span style="color: #8b0000;" >&#8216;</span><span style="color: gray;" ></p>
<p></span><span style="color: maroon;" >4</span><span style="color: gray;" > </span><span style="color: maroon;" >2</span><span style="color: gray;" > </span><span style="color: blue;" >FETCH_R</span><span style="color: gray;" > </span><span style="color: blue;" >local</span><span style="color: gray;" > $</span><span style="color: maroon;" >2</span><span style="color: gray;" >, </span><span style="color: #8b0000;" >&#8216;</span><span style="color: red;" >i</span><span style="color: #8b0000;" >&#8216;</span><span style="color: gray;" ></p>
<p></span><span style="color: maroon;" >3</span><span style="color: gray;" > </span><span style="color: blue;" >CONCAT</span><span style="color: gray;" > ~</span><span style="color: maroon;" >3</span><span style="color: gray;" >, $</span><span style="color: maroon;" >2</span><span style="color: gray;" >,</span></span><span style="font-family: Courier New;" ><span style="color: #8b0000;" >&#8216;</span><span style="color: red;" >+that+has+been+echoed+to+screen</span><span style="color: #8b0000;" >&#8216;</span></span><span style="font-family: Courier New;" ><span style="color: gray;" > </span><span style="color: gray;" ></p>
<p></span><span style="color: maroon;" >4</span><span style="color: gray;" > </span><span style="color: green;" >ECHO</span><span style="color: gray;" > ~</span><span style="color: maroon;" >3</span><span style="color: gray;" ></p>
<p></span><span style="color: maroon;" >6</span><span style="color: gray;" > </span><span style="color: maroon;" >5</span><span style="color: gray;" > </span><span style="color: green;" >RETURN</span><span style="color: gray;" > </span><span style="color: maroon;" >1</span><span style="color: gray;" ></p>
<p></span><span style="color: maroon;" >6</span><span style="color: gray;" > </span><span style="color: blue;" >ZEND_HANDLE_EXCEPTION</span></span></div>
</div>
<p>我们可以看到，源文件中的注释，在op code中，已经没有了，所以不用担心注释太多会影响你的脚本执行时间（实际上，它是会影响ZE的词法处理阶段的用时而已）。</p>
<p>现在我们来一条一条的分析这段op codes，每一条op code 又叫做一条op_line，都由如下7个部分，在zend_compile.h中，我们可以看到如下定义：</p>
<div class="hl-surround" >
<div class="hl-main"  style="margin-left: 40px;" ><span class="hl-types" >struct</span><span style="color: gray;" > </span><span style="color: blue;" >_zend_op</span><span style="color: gray;" > </span><span style="color: olive;" >{</span><span style="color: gray;" ></p>
<p></span><span style="color: blue;" >opcode_handler_t</span><span style="color: gray;" > </span><span style="color: blue;" >handler</span><span style="color: gray;" >;</p>
<p></span><span style="color: blue;" >znode</span><span style="color: gray;" > </span><span style="color: blue;" >result</span><span style="color: gray;" >;</p>
<p></span><span style="color: blue;" >znode</span><span style="color: gray;" > </span><span style="color: blue;" >op1</span><span style="color: gray;" >;</p>
<p></span><span style="color: blue;" >znode</span><span style="color: gray;" > </span><span style="color: blue;" >op2</span><span style="color: gray;" >;</p>
<p></span><span style="color: blue;" >ulong</span><span style="color: gray;" > </span><span style="color: blue;" >extended_value</span><span style="color: gray;" >;</p>
<p></span><span style="color: blue;" >uint</span><span style="color: gray;" > </span><span style="color: blue;" >lineno</span><span style="color: gray;" >;</p>
<p></span><span style="color: blue;" >zend_uchar</span><span style="color: gray;" > </span><span style="color: blue;" >opcode</span><span style="color: gray;" >;</p>
<p></span><span style="color: olive;" >}</span><span style="color: gray;" >;</span></div>
</div>
<p>其中，opcode字段指明了这操作类型，handler指明了处理器，然后有俩个操作数，和一个操作结果。</p>
<ol>
<li>FETCH_W, 是以写的方式获取一个变量，此处是获取变量名”i”的变量于$0（*zval）。</li>
<li>将字符串”this+is+a+string”赋值(ASSIGN)给$0</li>
<li>字符串连接</li>
<li>显示</li>
</ol>
<p>可以看出，这个很类似于很多同学大学学习编译原理时候的三元式，不同的是，这些中间代码会被Zend VM（Zend虚拟机）直接执行。</p>
<p>真正负责执行的函数是，zend_execute, 查看zend_execute.h:</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
</pre>
<p>可以看出， zend_execute接受zend_op_array*作为参数。 </p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
 struct _zend_op_array {
    /* Common elements */
    zend_uchar type;
    char *function_name;
    zend_class_entry *scope;
    zend_uint fn_flags;
    union _zend_function *prototype;
    zend_uint num_args;
    zend_uint required_num_args;
    zend_arg_info *arg_info;
    zend_bool pass_rest_by_reference;
    unsigned char return_reference;
    /* END of common elements */

    zend_uint *refcount;

    zend_op *opcodes;
    zend_uint last, size;

    zend_compiled_variable *vars;
    int last_var, size_var;

    zend_uint T;

    zend_brk_cont_element *brk_cont_array;
    zend_uint last_brk_cont;
    zend_uint current_brk_cont;

    zend_try_catch_element *try_catch_array;
    int last_try_catch;

    /* static variables support */
    HashTable *static_variables;

    zend_op *start_op;
    int backpatch_count;

    zend_bool done_pass_two;
    zend_bool uses_this;

    char *filename;
    zend_uint line_start;
    zend_uint line_end;
    char *doc_comment;
    zend_uint doc_comment_len;

    void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
</pre>
<p>可以看到，zend_op_array的结构和zend_function的结构很像（参看我的其他文章）， 对于在全局作用域的代码，就是不包含在任何function内的op_array,它的function_name为NULL。结构中的opcodes保存了属于这个op_array的op code数组，zend_execute会从start_op开始，逐条解释执行传入的每条op code, 从而实现我们PHP脚本想要的结果。
</p>
<p> 下一次，我将介绍PHP变量的灵魂 &#8211; zval, 你将会看到PHP是如何实现它的变量传递，类型戏法，等等。<br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/11</a>, <a href="http://www.apear.cn"  rel="external nofollow"  class="url" >xinquan</a> writes: en, not bad ... continue ...</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/11</a>, <a href="http://icyriver.net"  rel="external nofollow"  class="url" >冰的河</a> writes: 不错，尤其是右手代码，左手诗，很赞。要坚持，俗话说：一个人，吟一首诗并不难；难的是，吟一辈子诗。</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/12</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 恩，有功夫我就写点，呵呵；）</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/13</a>, yongtao.pang writes: 看zval去啦，有人劈荆斩棘真好</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/18</a>, <a href="http://www.lffly.com"  rel="external nofollow"  class="url" >lffly</a> writes: 写的不错。订阅了你的博客</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/21</a>, <a href="http://blog.csdn.net/ylcz"  rel="external nofollow"  class="url" >ylcz</a> writes: 太深奥了</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/23</a>, Leftwater writes: 决定长期阅读学习博主文章~</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/24</a>, liexusong writes: 你出PHP内核的书的话，我一定买！！</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/08/25</a>, <a href="http://glemir.xplore.cn"  rel="external nofollow"  class="url" >glemir</a> writes: 冰之河说：“要坚持，俗话说：一个人，吟一首诗并不难；难的是，吟一辈子诗”
xinquan的目标是要吟一辈子“唐诗”。</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/09/08</a>, sue writes: 传说中的“右手诗”在哪里啊。。</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/10/13</a>, highjade writes: 学习~</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/11/20</a>, <a href="http://www.yvdeo.com"  rel="external nofollow"  class="url" >smilesoul</a> writes: 老大啊  你是我的偶像啊   你怎么学这么深  佩服佩服！

能不能指点下怎么学写一个php的c扩展

需要具备学习哪些知识，能不能谈谈经验</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2008/12/07</a>, guangtianxia writes: 支持这种精神。</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2009/04/22</a>, <a href="http://www.self-trust.cn"  rel="external nofollow"  class="url" >coolboy0316</a> writes: 太深奥了，不是很懂.
学习....</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2009/05/06</a>, <a href="http://www.coudou.com"  rel="external nofollow"  class="url" >dyh1919</a> writes: 编译原理没学好，看不懂</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2009/05/30</a>, <a href="http://52037872.cn"  rel="external nofollow"  class="url" >不是什么区</a> writes: 不错，既然有现成了我就懒得写了，不介意我转走了吧？</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2009/10/09</a>, <a href="http://no"  rel="external nofollow"  class="url" >zhifu</a> writes: 强人，我也做了快一年的PHPER，最近在写项目，总是遇到很棘手的问题，导致最后学得去研究底层，现在才发现，要想把技术做好，真得研究底层。

还是很感谢，楼主有这样的精力去研究，并开源给我们，小弟真的十分感谢呀</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2010/02/01</a>, <a href="http://www.phpfamily.cn"  rel="external nofollow"  class="url" >xiaokai</a> writes: 很是深奥, 但是总一天我会弄懂的..</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2010/05/15</a>, phper writes: 博主的文章写得太好了！偶像,我要长期关注</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2010/05/28</a>, 人海孤鸿 writes: 赞</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2010/07/23</a>, <a href="http://www.commentset.com"  rel="external nofollow"  class="url" >mahone</a> writes: 非常可惜啊，不是计算机专业，编译原理和汇编都没学过……悲剧啊……看不懂文章</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2010/07/23</a>, <a href="http://www.commentset.com"  rel="external nofollow"  class="url" >mahone</a> writes: 不是计算机专业，没学过编译原理和汇编，看不懂文章……可悲……</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2010/07/29</a>, <a href="http://www.g.cn"  rel="external nofollow"  class="url" >google</a> writes: 翻山越岭终于找到这篇好文章</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2010/08/26</a>, xiaobao writes: 上面那张图对吗，鸟哥？
require或者函数是编译的时候一并编译了，还是等到执行的时候，再回头去编译？好像应该是前者吧。</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2011/03/11</a>, <a href="http://blog.bjmayor.com/?p=138"  rel="external nofollow"  class="url" >怪异的js编码问题 | bjmayor的个人空间</a> writes: [...] 深入浅出PHP(Exploring PHP) [...]</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=186"  rel="external nofollow"  class="url" >深入浅出PHP(Exploring PHP) | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/11/147.html [...]</li><li><a href="http://www.laruence.com/2008/08/11/147.html" >2011/09/02</a>, <a href="http://warpigallen.sinaapp.com/?p=9"  rel="external nofollow"  class="url" >深入浅出PHP(Exploring PHP) | warpig_allen&#039;s blog</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/11/147.html [...]</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li><li><a href="http://www.laruence.com/2007/12/16/308.html"  title="PHP:Header" >PHP:Header</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/11/147.html/feed</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>揭秘TSRM(Introspecting TSRM)</title>
		<link>http://www.laruence.com/2008/08/03/201.html</link>
		<comments>http://www.laruence.com/2008/08/03/201.html#comments</comments>
		<pubDate>Sun, 03 Aug 2008 06:19:07 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[TSRM]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=201</guid>
		<description><![CDATA[   <p>如果你曾经做过PHP的扩展，或者研究过PHP的源码，你就会看到这个东西到处都在。但是关于这个东西是什么，却鲜有资料叙及。</p>
      <p>对于这个东西是什么，最常见的回答就是“你不用关心这个是什么，你只要在‘这里’‘那里’用上就是了，如果编译器告诉你缺少tsrm_ls，加上就好了 ”。这个答案虽然是一种很敷衍的回答，但其实也是有一定道理的，因为Zend Engine把这个宏搞的太复杂，并且对于一个初学PHP扩展的开发者来说，了解它是什么也没有太大的益处。
    而我是一个喜欢追根究底的人。所以，如果你现在刚好比较闲，并有耐性了解这个东西是什么，那么就请继续读下去...</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/03/201.html"  title="Permanet Link to 揭秘TSRM(Introspecting TSRM)" >http://www.laruence.com/2008/08/03/201.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>如果你曾经做过PHP的扩展，或者研究过PHP的源码，你就会看到这个东西到处都在。但是关于这个东西是什么，却鲜有资料叙及。</p>
<p>对于这个东西是什么，最常见的回答就是“你不用关心这个是什么，你只要在‘这里’‘那里’用上就是了，如果编译器告诉你缺少tsrm_ls，加上就好了 ”。这个答案虽然是一种很敷衍的回答，但其实也是有一定道理的，因为Zend Engine把这个宏搞的太复杂，并且对于一个初学PHP扩展的开发者来说，了解它是什么也没有太大的益处。<br/>
    而我是一个喜欢追根究底的人。所以，如果你现在刚好比较闲，并有耐性了解这个东西是什么，那么就请继续读下去。</p>
<p>    名词解释：<br/>
TSRM<br/>
         线程安全资源管理器(Thread Safe Resource Manager)，这是个尝尝被忽视，并很少被人说起的“层”(layer), 她在PHP源码的/TSRM目录下。一般的情况下，这个层只会在被指明需要的时候才会被启用(比如,Apache2+worker MPM,一个基于线程的MPM)，对于Win32下的Apache来说，是基于多线程的，所以这个层在Win32下总是被启用的。<br/>
ZTS<br/>
Zend线程安全(Zend Thread Safety)，当TSRM被启用的时候，就会定义这个名为ZTS的宏。<br/>
tsrm_ls<br/>
TSRM存储器(TSRM Local Storage)，这个是在扩展和Zend中真正被实际使用的指代TSRM存储的变量名。<br/>
TSRMLS_??<br/>
   这是一族(4个)宏，用来根据ZTS宏被定义与否来实现TSRM。4个宏如下：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
#define TSRMLS_C   tsrm_ls
#define TSRMLS_D   void  *** tsrm_ls
#define TSRMLS_CC  ,tsrm_ls
#define TSRMLS_DS  ,void  ***tsrm_ls   //注意有个逗号
 </pre>
<p>   我们都知道，在C或者PHP编程中，要在多个函数中访问同一个变量有俩种方式，一种是通过参数传递，比如下面的代码：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
    #include &lt;stdio.h&gt;

    void output_func(char *message)
    {
        printf(&quot;%s\n&quot;, message);
    }

    int main(int argc, char *argv[])
    {
        output_func(argv[0]);

        return 0;
    }
 </pre>
<p>  另外一种方式是，通过在函数的高一级作用域中存储这个变量(当然，对于PHP，要显示的指明Global变量(这个原因和PHP的作用域的实现－活动表有关系，本处不涉及，我会在将来的某篇文章中介绍她)，如：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
    #include &lt;stdio.h&gt;

    char *message;

    void output_func(void)
    {
        printf(&quot;%s\n&quot;, message);
    }

    int main(int argv, char *argv[])
    {
        message = argv[0];
        output_func();

        return 0;
}
</pre>
<p>对于在PHP使用第二种方式来说，一般的单线 程模型比如PHP CLI方式，Apache1，或者Apache2+prefork MPM(也是一种多进程模型)，可以放心的被使用，也不会出错。全局变量在MINIT/RINIT的时候被创建，然后在整个进程运行时/请求处理期都能被 访问到，然后在MSHUTDOW/RSHUTDOWN的时候被释放。<br/>
         但是在多线程的模型下，这种方式就不在安全了，比如Apache2+worker MPM和IIS。在这种情况下，所有的线程共享同一个进程的地址空间，也就说，多个线程共用一个全局变量，这个时候就会产生竞争。用C程序员的方式来说: 这个时候的全局变量是非线程安全的。<br/>
   为了解决这个问题，并和单线程模式兼容，Zend使用了称作“Non_global Globals”的机制。这个机制的主要思想就是，对于多线程模型来说，每当一个新的线程被创建，就单独的分配一块内存，这块内存存储着一个全局变量的副 本。而这块内存会被一个Vector串起来，由Zend统一管理。为了说明这个方式，咱们看看如下的例子：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
    typedef struct _zend_myextension_globals {
        int foo;
        char *bar;
    } zend_myextension_globals;

    #ifdef ZTS  //如果TSRM被启用
    int myextension_globals_id;
    #else
    zend_myextension_globals myextension_globals;
    #endif

    /* 当线程被创建的时候调用 */
    static void php_myextension_globals_ctor(zend_myextension_globals *myext_globals TSRMLS_DC)
    {
        myext_globals-&gt;foo = 0;
        myext_globals-&gt;bar = NULL;
    }

    /* 线程结束的时候被调用 */
    static void php_myextension_globals_dtor(zend_myextension_globals *myext_globals TSRMLS_DC)
    {
        if (myext_globals-&gt;bar) {
            efree(myext_globals-&gt;bar);
        }
    }

    PHP_MINIT_FUNCTION(myextension)
    {
    #ifdef ZTS
        ts_allocate_id(&amp;myextension_globals_id, sizeof(zend_myextension_globals),
                       php_myextension_globals_ctor, php_myextension_globals_dtor);
    #else
        php_myextension_globals_ctor(&amp;myextension_globals TSRMLS_CC);
    #endif

        return SUCCESS;
    }

    PHP_MSHUTDOWN_FUNCTION(myextension)
    {
    #ifndef ZTS
        php_myextension_globals_dtor(&amp;myextension_globals TSRMLS_CC);
    #endif

        return SUCCESS;
    }
</pre>
<p>  这个例子开始的时候向TSRM层申明了一个全局变量” zend_myextension_globals”，</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
        ts_allocate_id(&amp;myextension_globals_id, sizeof(zend_myextension_globals),
                       php_myextension_globals_ctor, php_myextension_globals_dtor);
</pre>
<p> 他指明了要申请的全局变量的大小，创建器和析构器。并讲这个生成的全局变量在Vector中的偏移量(Index)保存在了myextension_globals_id中。而对于没有启用TSRM的情况，这个全局变量只是简单的被创建。<br/>
 如果你问我“为什么在没有启用TSRM的情况下还会有TSRMLS_CC?”,那说明你现在还没有被我弄糊涂;)，恩，在ZTS没有被设置的情况下(没有启用TSRM)，TSRMLS_CC会被编译器替换为空，因为:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
     #ifdef ZTS
              #define TRSMLS_CC  ,tsrm_ls
  #else
      #define TSRMLS_CC
  #endif
</pre>
<p>   在没有启用TSRM的情况下还指明TSRMLS_CC的原因仅仅是为了保持代码的一致性。</p>
<p>   恩，现在已经设置了全局变量，那么接下来的问题就是，我们如果去访问它呢？看看如下的代码：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
    #ifdef ZTS
    # define   MYEXTENSION_G(v)     \
                 (((zend_myextension_globals*)(*((void ***)tsrm_ls))[(myextension_globals_id)-1])-&gt;v)
    #else
    # define   MYEXTENSION_G(v)     (myextension_globals.v)
    #endif
 </pre>
<p>呵呵，明白了吧？ 在ZTS没有被设置的情况下，宏MYEXTENSION_G(V)简单的被等价于全局变量myextension_globals.v，而对于启用了TSRM的情况，MYEXTENSION_G(V)会被转化成在Vector中根据my_extension_globals_id来查找到要访问的全局变量。<br/>
现在，只要你在你的代码中，使用MYEXTENSION_G来访问你的全局变量，并在要使用这个全局变量的函数参数列表中添加上TSRMLS_CC，那么就能保证在单线程和多线程模型下的线程安全，和代码一致性。：）<br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/03/201.html" >2008/10/26</a>, <a href="http://hi.baidu.com/jackywdx"  rel="external nofollow"  class="url" >jackywdx</a> writes: 哦，原来这样，前两天正一直在查ZTS这个东东呢，结果一直查不到。呵呵~</li><li><a href="http://www.laruence.com/2008/08/03/201.html" >2010/05/18</a>, <a href="http://topsy.com/trackback?utm_source=pingback&#038;utm_campaign=L2&#038;url=http://www.laruence.com/2008/08/03/201.html"  rel="external nofollow"  class="url" >Tweets that mention 揭秘TSRM(Introspecting TSRM) | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by MC.Spring, sagasw. sagasw said: LuaPython都有类似的概念Env,不算稀奇 RT @mcspring http://bit.ly/9hCPj6 看了 @laruence 同学的这篇文章才明白PHP中的TSRM鱼TSRMLS_?簇名字的含义,缩写真的是太强大了,特别是在C语言中 [...]</li><li><a href="http://www.laruence.com/2008/08/03/201.html" >2011/06/05</a>, liuzhiqiang writes: 看了上面的例子，有个问题还是没弄明白，按照这个(((zend_myextension_globals*)(*((void ***)tsrm_ls))[(myextension_globals_id)-1])-&gt;v)的意思，myextension_globals是放在tsrm_ls里面的，可是这个是如何放进去的呢？

php_myextension_globals_ctor这个函数只是在参数列表里面包含了void ***tsrm_ls，函数体只是初始化变量，并未讲变量村到tsrm_ls中啊。

貌似可能是ts_allocate_id这个函数在完成这个动作，但是怎么实现的呢？

如果真是这样的话，php_myextension_globals_ctor这个函数是不是就不许要第二个参数了？ 即void ***tsrm_ls??

不知道我理解的对不对，请指教啊，十分感谢！！</li><li><a href="http://www.laruence.com/2008/08/03/201.html" >2011/06/06</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @liuzhiqiang 大体上是这样, 根据thread得到一个thread_id, 根据这个thread_id, 在一个全局的内存空间后给这个thread分配所有申明的全局变量大小总和的空间, 也就是tsrm_ls, 而在每一个模块初始化的时候, 都会分配一个模块id, 也就是对应在tsrm_ls中的偏移.</li><li><a href="http://www.laruence.com/2008/08/03/201.html" >2011/06/06</a>, liuzhiqiang writes: tsrm_ls中放的是当前线程还是所有线程的全局变量？这里说的模块和线程之间是什么关系？</li><li><a href="http://www.laruence.com/2008/08/03/201.html" >2011/06/06</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @liuzhiqiang 当前线程的全局变量, 模块就是扩展, 每一个扩展都可以有自己的全局变量(不是语言意义的全局变量,而是module_globals)</li><li><a href="http://www.laruence.com/2008/08/03/201.html" >2011/06/06</a>, liuzhiqiang writes: OK，这样就和代码中的逻辑对上了，多谢多谢啊。</li><li><a href="http://www.laruence.com/2008/08/03/201.html" >2011/06/06</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @liuzhiqiang  恩, 另外, 本文是为了解释TSRM所以设计了一些场景, 而一般的, 如果是模块的globals, 是不需要显示自己调用ts_allocate_id的, PHP的模块加载会做这一步工作</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/03/201.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>深入理解PHP原理之Opcodes</title>
		<link>http://www.laruence.com/2008/06/18/221.html</link>
		<comments>http://www.laruence.com/2008/06/18/221.html#comments</comments>
		<pubDate>Wed, 18 Jun 2008 10:40:52 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=221</guid>
		<description><![CDATA[ 最近要给Yahoo的同事们做一个关于PHP和Apache处理请求的内部机制的讲座，刚好写了些关于Opcodes的文字，就发上来了，这个文章基于 Sara Golemon的 Understanding OPcode]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/06/18/221.html"  title="Permanet Link to 深入理解PHP原理之Opcodes" >http://www.laruence.com/2008/06/18/221.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>     最近要给Yahoo的同事们做一个关于PHP和Apache处理请求的内部机制的讲座，刚好写了些关于Opcodes的文字，就发上来了，这个文章基于 Sara Golemon大师的《Understanding OPcode》</p>
<p>    Opcode是一种PHP脚本编译后的中间语言，就像Java的ByteCode,或者.NET的MSL，举个例子，比如你写下了如下的PHP代码：</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
 &lt;?php
   echo &quot;Hello World&quot;;
   $a = 1 + 1;
   echo $a;
?&gt;
</pre>
<p>  PHP执行这段代码会经过如下4个步骤(确切的来说，应该是PHP的语言引擎Zend)</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1.Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)
2.Parsing, 将Tokens转换成简单而有意义的表达式
3.Compilation, 将表达式编译成Opocdes
4.Execution, 顺次执行Opcodes，每次一条，从而实现PHP脚本的功能。
</pre>
<p>   题外话:现在有的Cache比如APC,可以使得PHP缓存住Opcodes，这样，每次有请求来临的时候，就不需要重复执行前面3步，从而能大幅的提高PHP的执行速度。</p>
<p>   那什么是Lexing?  学过编译原理的同学都应该对编译原理中的词法分析步骤有所了解，Lex就是一个词法分析的依据表。 Zend/zend_language_scanner.c会根据Zend/zend_language_scanner.l(Lex文件),来输入的 PHP代码进行词法分析，从而得到一个一个的“词”，PHP4.2开始提供了一个函数叫token_get_all,这个函数就可以讲一段PHP代码 Scanning成Tokens；<br/>
  如果用这个函数处理我们开头提到的PHP代码，将会得到如下结果:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
Array
(
    [0] =&gt; Array
        (
           [0] =&gt; 367
           [1] =&gt;  Array
        (
            [0] =&gt; 316
            [1] =&gt; echo
        )
    [2] =&gt; Array
        (
            [0] =&gt; 370
            [1] =&gt;
        )
    [3] =&gt; Array
        (
            [0] =&gt; 315
            [1] =&gt; &quot;Hello World&quot;
        )
    [4] =&gt; ;
    [5] =&gt; Array
        (
            [0] =&gt; 370
            [1] =&gt;
        )
    [6] =&gt; =
    [7] =&gt; Array
        (
            [0] =&gt; 370
            [1] =&gt;
        )
    [8] =&gt; Array
        (
            [0] =&gt; 305
            [1] =&gt; 1
        )
    [9] =&gt; Array
        (
            [0] =&gt; 370
            [1] =&gt;
        )
    [10] =&gt; +
    [11] =&gt; Array
        (
            [0] =&gt; 370
            [1] =&gt;
        )
    [12] =&gt; Array
        (
            [0] =&gt; 305
            [1] =&gt; 1
        )
    [13] =&gt; ;
    [14] =&gt; Array
        (
            [0] =&gt; 370
            [1] =&gt;
        )
    [15] =&gt; Array
        (
            [0] =&gt; 316
            [1] =&gt; echo
        )
    [16] =&gt; Array
        (
            [0] =&gt; 370
            [1] =&gt;
        )
    [17] =&gt; ;
)
</pre>
<p>    分析这个返回结果我们可以发现，源码中的字符串，字符，空格，都会原样返回。每个源代码中的字符，都会出现在相应的顺序处。而，其他的比如标签，操作符，语句，都会被转换成一个包含俩部分的Array: Token ID (也就是在Zend内部的改Token的对应码，比如,T_ECHO,T_STRING)，和源码中的原来的内容。<br/>
  接下来，就是Parsing阶段了，Parsing首先会丢弃Tokens Array中的多于的空格，然后将剩余的Tokens转换成一个一个的简单的表达式</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1.echo a constant string
2.add two numbers together
3.store the result of the prior expression to a variable
4.echo a variable
</pre>
<p>然后就改Compilation阶段了，它会把Tokens编译成一个个op_array, 每个op_arrayd包含如下5个部分：</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1.Opcode数字的标识，指明了每个op_array的操作类型，比如add , echo
2.结果       存放Opcode结果
3.操作数1  给Opcode的操作数
4.操作数2
5.扩展值   1个整形用来区别被重载的操作符
</pre>
<p>  比如，我们的PHP代码会被Parsing成:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
* ZEND_ECHO     'Hello World'
* ZEND_ADD       ~0 1 1
* ZEND_ASSIGN  !0 ~0
* ZEND_ECHO     !0
</pre>
<p>呵呵，你可能会问了，我们的$a去那里了？</p>
<p>       恩，这个要介绍操作数了，每个操作数都是由以下俩个部分组成：</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
a)op_type : 为IS_CONST, IS_TMP_VAR, IS_VAR, IS_UNUSED, or IS_CV

b)u,一个联合体，根据op_type的不同，分别用不同的类型保存了这个操作数的值(const)或者左值(var)
</pre>
<p>       而对于var来说，每个var也不一样</p>
<p>IS_TMP_VAR, 顾名思义，这个是一个临时变量，保存一些op_array的结果，以便接下来的op_array使用，这种的操作数的u保存着一个指向变量表的一个句柄（整数），这种操作数一般用~开头，比如~0,表示变量表的0号未知的临时变量</p>
<p>IS_VAR 这种就是我们一般意义上的变量了,他们以$开头表示</p>
<p>IS_CV 表示ZE2.1/PHP5.1以后的编译器使用的一种cache机制，这种变量保存着被它引用的变量的地址，当一个变量第一次被引用的时候，就会被CV起来，以后对这个变量的引用就不需要再次去查找active符号表了，CV变量以！开头表示。</p>
<p>      这么看来，我们的$a被优化成!0了。<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/08/16</a>, <a href="http://www.laruence.com/2008/08/16/301.html"  rel="external nofollow"  class="url" >扩展PHP[Extending PHP](1) | 风雪之隅</a> writes: [...] 你所编写的脚本，最终都会被转换成C代码来执行。 这个和我在以前文章中(深入理解PHP原理之Opcodes)介绍的opcode并不冲突， [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/08/27</a>, chen writes: 本人学艺不精,看了你的文章后有很多疑问,这个php的opcode怎么能够得到啊?能具体说说吗?</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/08/31</a>, Anonymous writes: 以后多向你老人家学习</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/09/11</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: to chen, 可以通过vld扩展获取. 
关于vld的原理,我记得我以前的文章介绍过.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/10/05</a>, xiaoj writes: PHP Opcode Dumper，这个工具可以查看到编译后的opcodes</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/10/10</a>, highjade writes: 学习。</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/10/10</a>, 熊林 writes: 来看看，不错</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/10/19</a>, Anonymous writes: 左手源码，右手诗，吾甚向往之。。。。。。</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2008/11/20</a>, <a href="http://www.laruence.com/2008/11/20/630.html"  rel="external nofollow"  class="url" >深入理解PHP原理之foreach | 风雪之隅</a> writes: [...] 深入理解PHP原理之Opcodes [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2009/08/18</a>, wan writes: 好文章，已认真阅读，请问为什么每次生成的 opcodes 的最后总是会有这么一条指令： * ZEND_HANDLE_EXCEPTION ， 请指点。谢谢</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/01/26</a>, <a href="http://www.topthesis.com"  rel="external nofollow"  class="url" >Ellen22</a> writes: Wow, hot topic related to this good topic. Could please tell me how long period of time that will take? Just because I want to finish the dissertation idea or probably it would be better to determine the <a href="http://www.topthesis.com"  rel="nofollow" >thesis writing</a>. Thnx.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/03/30</a>, yoyoz writes: <a href="http://www.sanwatches.com/"  rel="nofollow" >replica watches</a><a href="http://www.sanwatches.com/rolex-watches.html"  rel="nofollow" >rolex watches</a><a href="http://www.sanwatches.com/breitling-watches.html"  rel="nofollow" >breitling watches</a><a href="http://www.sanwatches.com/cartier-watches.html"  rel="nofollow" >cartier watches</a><a href="http://www.sanwatches.com/omega-watches.html"  rel="nofollow" >omega watches</a><a href="http://www.sanwatches.com/tag_heuer-watches.html"  rel="nofollow" >tag heuer watches</a>

<a href="http://www.watchesfan.com/"  rel="nofollow" >replica watches</a><a href="http://www.watchesfan.com/rolex-watches.html"  rel="nofollow" >rolex</a><a href="http://www.watchesfan.com/breitling-watches.html"  rel="nofollow" >breitling</a><a href="http://www.watchesfan.com/cartier-watches.html"  rel="nofollow" >cartier</a><a href="http://www.watchesfan.com/omega-watches.html"  rel="nofollow" >omega</a><a href="http://www.watchesfan.com/tag_heuer-watches.html"  rel="nofollow" >tag heuer</a>

<a href="http://www.corwatches.com/"  rel="nofollow" >replica watches</a><a href="http://www.corwatches.com/rolex-watches.html"  rel="nofollow" >replica rolex</a><a href="http://www.corwatches.com/breitling-watches.html"  rel="nofollow" >replica breitling</a><a href="http://www.corwatches.com/cartier-watches.html"  rel="nofollow" >replica cartier</a><a href="http://www.corwatches.com/omega-watches.html"  rel="nofollow" >replica omega</a><a href="http://www.corwatches.com/tag_heuer-watches.html"  rel="nofollow" >replica tag heuer</a>

<a href="http://www.pocwatches.com/"  rel="nofollow" >replica watches</a><a href="http://www.pocwatches.com/rolex-watches.html"  rel="nofollow" >fake rolex</a><a href="http://www.pocwatches.com/breitling-watches.html"  rel="nofollow" >fake breitling</a><a href="http://www.pocwatches.com/cartier-watches.html"  rel="nofollow" >fake cartier</a><a href="http://www.pocwatches.com/omega-watches.html"  rel="nofollow" >fake omega</a><a href="http://www.pocwatches.com/tag_heuer-watches.html"  rel="nofollow" >fake tag heuer</a>JJ.03.30</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/04/21</a>, <a href="http://www.shoppinglouisvuitton.com/"  rel="external nofollow"  class="url" >nanninghechi</a> writes: Jazzy clothes go well with relations of <a href="http://www.shoppinglouisvuitton.com"  rel="nofollow" >Louis Vuitton</a> having unadorned devise. You should to respect your style when choosing  your right family of london jewelry. Nevertheless it is a big inquiry  for many women to highlight your personalities. For command, long  family <a href="http://www.shoppinglouisvuitton.com"  rel="nofollow" >Louis Vuitton handbags</a> will give the illusion of piece, so a ribbon with one effective  important touch a little above the bust line will look great Because of  this, the charms which could exactly pageant their purity and  innocence. In the decoration of the proceed. Therefore, You will never  be analogous to your dresses, age, career, complexion and with wheat  influence would look better by bearing jewels that are not so vivid,  for example the pearls or silver decorated family <a href="http://www.shoppinglouisvuitton.com"  rel="nofollow" >Louis Vuitton</a> classic charms . Ladies with dull wrecked are also good array for them.  Nothing will be more right than these brilliant jewels for these fleshy  ladies who will be looked sporting by taxing brilliant relations of <a href="http://www.shoppinglouisvuitton.com"  rel="nofollow" >Louis Vuitton wholesale</a>.  Girls taxing refined dresses should neither be disquiet about that will  lengthen the charms are proper for your face form nor completely  different from your face affect. Besides, agate and tawny are correct  for jewels that your causal dresses are too ordinary if the relations  of london are well matched with clothes. Some blush. Hope to help you!  Make reliable the look of your face. With an around face you want to  look for them. You know what! Women’s <a href="http://www.shoppinglouisvuitton.com"  rel="nofollow" >Louis Vuitton</a><a href="http://www.shoppinglouisvuitton.com/charms"  rel="nofollow" ></a> box is bottomless, just like women’s require for new jewelries. On you.  Hairstyle plays an important part In deference that sole judgment and  personal qualities will be displayed if you game them with a  well-intended trinkets with Some suggestions on choosing and matching  jewelries are as follow. Keep in mentality, the character of your <a href="http://www.shoppinglouisvuitton.com"  rel="nofollow" >Louis Vuitton</a><a href="http://www.shoppinglouisvuitton.com/bracelets"  rel="nofollow" ></a> jewelries should game small and elegant links of london heart which are easy, small, and other aspects to wish jewelries right.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/06/25</a>, <a href="http://www.collectionsdvd.com"  rel="external nofollow"  class="url" >Breitling</a> writes: With so many games streaming data from the <a href="http://www.collectionsdvd.com/comedy/hazel-dvd-collection.html"  rel="nofollow" ><strong>HAZEL</strong></a>  on the fly. The methodology for the tests was remarkably straight for ward first from <a href="http://www.collectionsdvd.com/comedy/hazel-dvd-collection.html"  rel="nofollow" ><strong>HAZEL DVD</strong></a>, then from hard disk. As the opportunity to install to <a href="http://www.collectionsdvd.com/comedy/hazel-dvd-collection.html"  rel="nofollow" ><strong>HAZEL DVD COLLECTION</strong></a>  is obviously a compelling argument for upgrading the hard disk.<a href="http://www.collectionsdvd.com/comedy/here-s-lucy-dvd-collection.html"  rel="nofollow" ><strong>HERE'S LUCY</strong></a></li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/06/25</a>, <a href="http://blog.csdn.com/jallin2001"  rel="external nofollow"  class="url" >jacky</a> writes: 好地方，学习了。</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/06/25</a>, <a href="http://blog.csdn.com/jallin2001"  rel="external nofollow"  class="url" >jacky</a> writes: 昨天我正好在看
《Pro PHP Patterns Frameworks Testing and More》
里面就谈到了lexing：
While PHP is not a compiled language, it resembles compiled languages in that PHP code
is converted into a binary format before actually being executed.

This transformation from programming language
to executable code is called 
&gt;&gt;&gt;lexing
because it transforms the lexical structure of PHP code into 
&gt;&gt;&gt;opcodes(numeric representation of PHP language elements).

维基百科上对于opcode(operation code)的解释：
is the portion of a machine language instruction that specifies the operation 
to be performed.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/06/30</a>, savannah writes: Keep in mind that many resources are available <a href="http://www.havewatches.com/tissot.html"  rel="nofollow" >fake tissot watches</a> milgauss watches replica cartier declaration watches <a href="http://www.ivywatches.com/tagheuer_slr.html"  rel="nofollow" >tag heuer slr watches</a> professional diver will have a watch that will be water <a href="http://www.bonniewatches.com/movado.html"  rel="nofollow" >movado</a> royal oak offshore 27 stood for the movements diameter in millimeters and C12 <a href="http://www.bonniewatches.com/rolex.html"  rel="nofollow" >rolex fake</a> worldwide as every woman knows that diamonds are a girls twenty 4 watches <a href="http://www.havewatches.com/"  rel="nofollow" >replica watches</a> insurance policies and exceptional multi-year warranties. <a href="http://www.bonniewatches.com/sohne.html"  rel="nofollow" >a lange and sohne watches</a> more and more appreciated by celebrities common people <a href="http://www.ivywatches.com/patek_twenty-4.html"  rel="nofollow" >fake patek philippe twenty 4 watches</a> changes came more unique watches but most of <a href="http://www.havewatches.com/"  rel="nofollow" >replica watches</a> watch imitations the company stays innovative <a href="http://www.expwatches.com/omega_collection.html"  rel="nofollow" >omega olympic collection</a> However since the 310 is going to become a premier <a href="http://www.expwatches.com/"  rel="nofollow" >replica watches</a> Golf Master has been developed as a mechanical <a href="http://www.expwatches.com/swissrolex.html"  rel="nofollow" >swiss rolex</a> replica bell and ross watches of the 21st century The selfwinding movement <a href="http://www.expwatches.com/panerai.html"  rel="nofollow" >fake panerai watches</a> Eco-Drive watch draws watch at all times from natural</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/07/16</a>, <a href="http://www.laruence.com/2010/07/16/1648.html"  rel="external nofollow"  class="url" >定制自己的PHP语法 | 风雪之隅</a> writes: [...] 如果你是不了解PHP的执行过程, 请先花点时间看看我之前的文章深入理解PHP原理之Opcodes: [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/07/23</a>, <a href="http://topsy.com/www.laruence.com/2008/06/18/221.html?utm_source=pingback&#038;utm_campaign=L2"  rel="external nofollow"  class="url" >Tweets that mention 深入理解PHP原理之Opcodes | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by 逸川, 逸川. 逸川 said: 我正在看：深入理解PHP原理之Opcodes | 风雪之隅 唉唉。。。功夫不到家，看不懂啊。。。 http://fl5.me/3hug3e [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/08/03</a>, <a href="http://www.laruence.com/2010/08/03/1697.html"  rel="external nofollow"  class="url" >深入理解PHP之异常机制 | 风雪之隅</a> writes: [...] 了解opcode(深入理解PHP原理之Opcodes的同学都知道, 在PHP5.3以前, 每一个可独立运行的op array(文件, 函数, 方法)的最后一条opcode都是ZEND_HANDLE_EXCEPTION, 而这个opcode是做什么用的呢? [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/08/04</a>, <a href="http://www.yeeger.com/?p=173"  rel="external nofollow"  class="url" >深入理解PHP原理之异常机制 | yeeger.com</a> writes: [...] 了解opcode(深入理解PHP原理之Opcodes的同学都知道, 在PHP5.3以前, 每一个可独立运行的op array(文件, 函数, 方法)的最后一条opcode都是ZEND_HANDLE_EXCEPTION, 而这个opcode是做什么用的呢? [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/08/17</a>, <a href="http://sky445.multiply.com"  rel="external nofollow"  class="url" >kikisu minii</a> writes: DVD players immediately can be made of extremely economical material, which brings us to our number one advantage. Once it's ended, you should see a new file in the rawdump folder, an ISO file, with the same term as anything game you unoriginal. So how preserve this befall achievable? Episode 48 (Don't Bug the Mosquitoes) Air Date: 12-09-1965. Finding a DVD <a href="http://www.bookmark4you.com/user/76061-pinkpappu"  rel="nofollow" >fake rolex</a> iPod converter with the aim of has a early conversion esteem is a necessity. Episode 26 (Angels on Ice: Part 2) Air Date: 09-21-1977. Or would you noticeably be skilled to pick out your specific music? When I pioneer in progress funing I was amazed at how I was adept to play songs that I loved within a few days. Along with the headphones, this a great way to keep your little tyke contentedly unavailable for the period of <a href="http://rock661.blog.com.es/"  rel="nofollow" >rolex replica watch</a> long <a href="http://moblog.net/view/936241/rolex"  rel="nofollow" >rolex replicas</a> stumble. Downloads are fast, easy to install and have user interfaces that are friendly.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/08/17</a>, kikisu minii writes: Features &amp; Performance: One of my choice features on the Sony DCR-DVD650 DVD Handycam camcorder is the erstwhile fashioned 'optical viewfinder' that is totally uncommon in camcorders currently. The new <a href="http://flove777.blog.de/"  rel="nofollow" >rolex replicas</a> family are storing memories and movies on DVD which can keep on everyplace from 25 years to 250 years. It mounts going on a vehicle's ceiling, typically flanked by the frontage and backside seats. How to orderly DVDs is cute easy if you know the individual aids to use and how to use them fittingly. The team that was sent to track becomes the hunted and are no complement for alien technology, but the make is highly-flavored with one of them. Episode 106 (The Sound of Children) Air Date: 02-05-1979. This format too uses the wretched laser, the alteration essence the higher compression of the video onslaught. Once you have your distributors in command you need to make your mind up how you want to persuade somebody to buy you goods. Corporal do well Klinger (Jamie Farr) provides comic relief with his first attempts to acquire a discharge by dressing in women's clothing, and Father Francis Mulcahy (William Christopher) adds give flavor to to a diverse cast of characters. This income that you need to have advantage product expertise so that you can actually rise the product you are buying. Step #6 - Cleaning the Laser Pickup - Now that you have <a href="http://flove775.journalhub.com/2010/08/11/hello-world/"  rel="nofollow" >swiss rolex replica watches</a> access to the laser jump back in, use a cotton mop and several isopropyl alcohol and gently wipe the lens. Lets play it, children get bored easily and to <a href="http://flove775.blog.co.uk/"  rel="nofollow" >rolex replica watch</a> your everyday jobs and pouring time turn easier, a Player is the way to go. Episode 40 (Indian Summer) Air Date: 10-27-1999.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/08/18</a>, <a href="http://www.jeecn.com/archives/695"  rel="external nofollow"  class="url" >PHP编译执行原理 &laquo; 网上商城系统开发</a> writes: [...] 本文地址: http://www.laruence.com/2008/06/18/221.html [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/08/23</a>, Lousesi minii writes: Such was his lot in life, resigned without end to powerful time only by looking at the <a href="http://eblog.lt/garryanist/"  rel="nofollow" >fake rolex watch</a> demonstrate clocks on times rectangle. Janice couldn�t judge her eyes! The prevalent trend of black watch over dials was in progress in Rolex. What they in reality give is a stone crystal. There are as much as necessary replica Rolex watches outmoded here in favor of them to like. Are you picture a six <a href="http://gred.rivblog.com"  rel="nofollow" >replica rolex</a> salary, compelling a Limousine and breathing in a hall? That is, the universe hold to have been more compressed formerly and rolex replicas were harder to happen near. A dressed indisputable Rolex watchband tin approach in a duo incarnations. �	Rolex replicas made in other Asian countries (but Japan and Korea);. Certawearingly, Rolex <a href="http://mein-blog.net/?w=geere"  rel="nofollow" >replica rolex watches</a> don�t include fake gold plating�. There are loads of Rolex model watches which exhibit stickers which display the logo of Rolex. The editorial discussion on the subject of why Rolex is a widely held big name in the world of watchmakers? Brand new for the year 2002, the company has launched micro-print a painstaking "tiara" sign into the crystal for the genuine Rolex watch, at the 6 o'clock scene. Only those watches arrive to the market which has lucratively accepted those investigate and others are sent ago. Up to this era, Rolex is banish a privately-owned one, and never went community to amicable its set to other shareholders.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/08/31</a>, <a href="http://www.jerseysusa.com"  rel="external nofollow"  class="url" >Wholesale NFL Jerseys</a> writes: Thank you for taking the time to publish this information very useful! 
I got a nice website for you guys too,Your favorite team's <a href="http://www.jerseysusa.com/nfl-jerseys/minnesota-vikings"  rel="nofollow" >Vikings jerseys</a> and <a href="http://www.jerseysusa.com/nfl-jerseys/new-orleans-saints"  rel="nofollow" >Saints jerseys</a> delivered right to your door.All at unbeliveble prices!!</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/09/01</a>, <a href="http://www.thenewusfl.com"  rel="external nofollow"  class="url" >Nicole Thompsen</a> writes: These drivers may sometimes come with additional functionality unavailable in worldwide drivers or other drivers not predestined for that special archetypal. If you find modern movie online, choosing the DVDs to rent is aided <a href="http://www.wedding-planner-gran-canaria.com/links_2.html"  rel="nofollow" >rolex replica watches</a> nit-picking and patron ratings and reviews. Even a situate of horror movies, romantic movies, battle <a href="http://www.wgsafesonline.com/useful-links.php"  rel="nofollow" >swiss rolex replica watches</a> and comedy movies are to be had in <a href="http://www.nusuevents.com.au/resources/entertainment-2.php"  rel="nofollow" >cheap rolex replicas </a> promote. Episode 48 (Fairy Tales Can Come True) Air Date: 10-25-1984. The new <a href="http://lindame33.onsugar.com/BrangelinaReplicas-10453895"  rel="nofollow" >swiss rolex replicas</a>, you will perhaps be tempted to get a shelf <a href="http://www.nusuevents.com.au/resources/jewellery-and-accessories-4.php"  rel="nofollow" >replica rolex watch</a> entertainment meeting point with your TV. The new <a href="http://www.thenewusfl.com/page7.html"  rel="nofollow" >rolex replicas</a> new <a href="http://www.tiretruckcenter.com/directory/detail/link-6638.html"  rel="nofollow" >fake rolex wactch</a> the years outdo, Bailey must contract with his own relations problems, his discontented dreams, and <a href="http://www.rakolighting.com/infosites/item-1107.html"  rel="nofollow" >fake rolex</a> burdens of the <a href="http://www.ceirysjewellery.co.uk/pages/links.php"  rel="nofollow" >cheap rolex replicas </a> Depression. Defeated, you have resigned yourself <a href="http://www.firstclasscars.co.uk/links.php"  rel="nofollow" >rolex replicas</a> the fact that you <a href="http://www.survivaloutdoorskills.com/links5.htm"  rel="nofollow" >replica rolex watch</a> pass on without interminably unlocking the sly of how to assigning DVD into iPod. Episode 39 (Officers Only) <a href="http://www.ahbsolutions.co.uk/useful-resources/links.asp?p=11"  rel="nofollow" >cheap rolex replicas </a> Date: 12-22-1973. One key <a href="http://www.iridisphotorestoration.com/photo_repair_links11.html"  rel="nofollow" >swiss replica rolex </a> of this function <a href="http://www.sincomart.com/ads.html"  rel="nofollow" >swiss rolex replicas</a> that it is used to retail copyrighted things. The new <a href="http://amanda564.obolog.com/jessica-replicas-858597"  rel="nofollow" >fake rolex wactch</a> nine successful <a href="http://www.zenithadventures.com/other2_resource.php"  rel="nofollow" >swiss replica rolex </a> to its honor, The X-Files is one of <a href="http://www.mysolarshop.com/apparel.html"  rel="nofollow" >fake rolex</a> <a href="http://www.prepaidcallscheap.com/links/links_realestate3.htm"  rel="nofollow" >rolex replica watches</a>-running sci-fi series in television history?. Using a DVD Collection Database <a href="http://www.tagegeldkonten.de/Bank-of-Scotland-Erfahrungen/bank-of-scotland-erfahrungen.html"  rel="nofollow" >fake rolex wactch</a> Ratings. The new <a href="http://jessicab231.cuisineblog.fr/"  rel="nofollow" >swiss rolex replica watches</a> new <a href="http://articlesgalore.info/resources/shopping.php"  rel="nofollow" >rolex replicas</a> <a href="http://open.salon.com/blog/dina677/2010/08/20/altidbulgarien"  rel="nofollow" >swiss rolex replicas</a> the scientific component of the crimson, depressed and bottle green components in <a href="http://www.agcommoditiesinc.com/links2.php"  rel="nofollow" >swiss replica rolex </a> colour <a href="http://www.howtoloseweightfastest.com/links/partners.html"  rel="nofollow" >rolex replica watches</a>. By informative the tale of world fame and internationally respected artist Big Pun, director Vlad Yudin brings us the exclusive real-life look at <a href="http://www.holidaylanguage.com/links.htm"  rel="nofollow" >swiss replica rolex </a> artist who changed the hip-hoedown <a href="http://www.postyourlink.info/ds.php"  rel="nofollow" >fake rolex wactch</a> and tap game forever. The Felicity ( <a href="http://www.gc-weddings.com/sponsored_links_4.html"  rel="nofollow" >fake rolex wactch</a> new <a href="http://www.tagegeldkonten.de/1-Empfehlung/1-empfehlung.html"  rel="nofollow" >rolex replicas</a> 3) DVD features a number of exciting episodes including the season premiere "The Christening" in which <a href="http://www.tagegeldkonten.de/Bank-of-Scotland-Erfahrungen/bank-of-scotland-erfahrungen.html"  rel="nofollow" >swiss rolex replicas</a> learns from Javier that a man is giving away his furniture before heartbreaking <a href="http://camroni944.bloging.ro/77550/saarcaa.html"  rel="nofollow" >fake rolex wactch</a> another utter. avi,.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/09/06</a>, <a href="http://louisvuittonwallets.net/"  rel="external nofollow"  class="url" >louis vuitton wallet</a> writes: <a href="http://louisvuittonwallets.net/"  rel="nofollow" >louis vuitton wallet</a>, <a href="http://louisvuittonwallets.net/"  rel="nofollow" >louis vuitton wallets</a>, <a href="http://louisvuittonwallets.net/"  rel="nofollow" >mens louis vuitton wallets</a>, <a href="http://louisvuittonwallets.net/"  rel="nofollow" >women louis vuitton wallets</a>.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/09/06</a>, <a href="http://iwallets.net/"  rel="external nofollow"  class="url" >wallets</a> writes: <a href="http://iwallets.net/"  rel="nofollow" >wallets</a>, <a href="http://iwallets.net/louis-vuitton-wallets-c-77.html"  rel="nofollow" >louis vuitton wallet</a>, <a href="http://iwallets.net/hermers-wallets-c-115.html"  rel="nofollow" >hermes wallet</a>, <a href="http://iwallets.net/gucci-wallets-c-78.html"  rel="nofollow" >gucci wallet</a>, <a href="http://iwallets.net/prada-wallets-c-104.html"  rel="nofollow" >prada wallet</a>.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/09/06</a>, <a href="http://replicaguccibelts.com/"  rel="external nofollow"  class="url" >replica gucci belts</a> writes: <a href="http://replicaguccibelts.com/"  rel="nofollow" >replica gucci belts</a>, Elegant <a href="http://replicaguccibelts.com/"  rel="nofollow" >replica gucci belt</a>, Fashion <a href="http://replicaguccibelts.com/"  rel="nofollow" >replica gucci belts for men</a>, <a href="http://replicaguccibelts.com/"  rel="nofollow" >replica gucci mens belt</a>.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/09/06</a>, <a href="http://womens-wallets.net/"  rel="external nofollow"  class="url" >women's wallet</a> writes: <a href="http://womens-wallets.net/"  rel="nofollow" >women's wallet</a>, <a href="http://womens-wallets.net/"  rel="nofollow" >louis vuitton womens wallet</a>, <a href="http://womens-wallets.net/"  rel="nofollow" >gucci womens wallet</a>, <a href="http://womens-wallets.net/"  rel="nofollow" >prada womens wallet</a>.</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2010/12/22</a>, <a href="http://www.osseye.com/?p=519"  rel="external nofollow"  class="url" >人自明 &raquo; 转：定制自己的PHP语法-在PHP中实现unless</a> writes: [...] 如果你是不了解PHP的执行过程, 请先花点时间看看我之前的文章深入理解PHP原理之Opcodes: [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/01/13</a>, <a href="http://www.wjmboss.cn/?p=958"  rel="external nofollow"  class="url" >定制自己的PHP语法-在PHP中实现unless | Jim的blog</a> writes: [...] 如果你是不了解PHP的执行过程, 请先花点时间看看我之前的文章深入理解PHP原理之Opcodes: [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/01/13</a>, <a href="http://blog.orgthing.com/2011/01/%e6%b7%b1%e5%85%a5%e7%90%86%e8%a7%a3php%e5%8e%9f%e7%90%86%e4%b9%8bopcodes/"  rel="external nofollow"  class="url" >深入理解PHP原理之Opcodes</a> writes: [...] 这么看来，我们的$a被优化成!0了。转载于: http://www.laruence.com/2008/06/18/221.html Opcodes, php 分享文章TwitterDiggFacebookDeliciousStumbleUponGoogle BookmarksLinkedInYahoo [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/02/23</a>, <a href="http://www.rabbitlog.net/archives/13"  rel="external nofollow"  class="url" >看php opcode的三个工具 | 兔子爱吃萝卜</a> writes: [...] 在阅读这篇文章的时候，发现命令都不能使，遂有了这篇文章。。。。 三个工具分别是： Tokenizer, Parseket, Vulcan Logic Disassembler. （1）phpsize找不到怎么办? sudo apt-get install php5-dev （2） install Parsekit sudo pecl install Parsekit 修改php.ini的so加载文件，加入parsekit.so （3） install Vulcan Logic Dumper You can get the source from SVN: svn co svn://svn.xdebug.org/svn/php/vld/trunk vld Here are the instructions to get it to work: cd into the newly checked-out directory. Create the configure script: phpize Now run &#8220;./configure&#8221; followed by &#8220;make install&#8221;. That&#8217;s it, if you now run PHP from the command line and add the -dvld.active=1 parameter VLD will spit out the opcodes: 修改php.ini的so加载文件，加入vld.so [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=210"  rel="external nofollow"  class="url" >深入理解PHP原理之Opcodes | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/06/18/221.html [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=288"  rel="external nofollow"  class="url" >深入理解PHP原理之异常机制 | 万维网黑客联盟</a> writes: [...] 了解opcode(深入理解PHP原理之Opcodes的同学都知道, 在PHP5.3以前, 每一个可独立运行的op array(文件, 函数, 方法)的最后一条opcode都是ZEND_HANDLE_EXCEPTION, 而这个opcode是做什么用的呢? [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/03/27</a>, <a href="http://blog.danotes.com/2010/11/13/php%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%e6%96%87%e7%ab%a0%e6%95%b4%e7%90%86.html"  rel="external nofollow"  class="url" >PHP源码分析文章整理 | NoNZero&#039;s Blog</a> writes: [...] 深入理解PHP原理之Opcodes [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/05/05</a>, <a href="http://www.ceallan.com/?p=523"  rel="external nofollow"  class="url" >军少领域 &raquo; 深入理解PHP原理之Opcodes</a> writes: [...] 本文地址: http://www.laruence.com/2008/06/18/221.html [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/05/12</a>, <a href="http://blog.jiandankuaile.com/archives/570"  rel="external nofollow"  class="url" >深入理解PHP原理之异常机制 - 简单快乐，享受生活</a> writes: [...] 了解opcode(深入理解PHP原理之Opcodes的同学都知道, 在PHP5.3以前, 每一个可独立运行的op array(文件, 函数, 方法)的最后一条opcode都是ZEND_HANDLE_EXCEPTION, 而这个opcode是做什么用的呢? [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/07/14</a>, <a href="http://blog.missyi.com/page_776.html"  rel="external nofollow"  class="url" >HTTP 204和205的应用 | 麦克 Magic Coder</a> writes: [...] 本文原地址: http://www.laruence.com/2008/06/18/221.html 标签: [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/09/02</a>, <a href="http://warpigallen.sinaapp.com/?p=11"  rel="external nofollow"  class="url" >深入理解PHP原理之Opcodes | warpig_allen&#039;s blog</a> writes: [...] 本文地址: http://www.laruence.com/2008/06/18/221.html [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/09/04</a>, <a href="http://www.panxianhai.com/php-apc.html"  rel="external nofollow"  class="url" >使用apc缓存 | 盘先海</a> writes: [...] PHP Cache (APC) 是一个开放自由的PHP opcode 缓存。它的目标是提供一个自由、 [...]</li><li><a href="http://www.laruence.com/2008/06/18/221.html" >2011/10/27</a>, <a href="http://sophp.sinaapp.com/?p=424"  rel="external nofollow"  class="url" >深入理解PHP原理之Opcodes | Focus On LAMP</a> writes: [...] 作者:laruence(http://www.laruence.com/) · 本文地址:&nbsp;http://www.laruence.com/2008/06/18/221.html · 转载请注明出处&nbsp;  作者：YoungerChen 发表于2011-10-4 17:37:42 原文链接   [...]</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2007/12/16/308.html"  title="PHP:Header" >PHP:Header</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/06/18/221.html/feed</wfw:commentRss>
		<slash:comments>44</slash:comments>
		</item>
		<item>
		<title>PHP:Header</title>
		<link>http://www.laruence.com/2007/12/16/308.html</link>
		<comments>http://www.laruence.com/2007/12/16/308.html#comments</comments>
		<pubDate>Sun, 16 Dec 2007 06:45:34 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend/PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=308</guid>
		<description><![CDATA[ PHP header()
   The function declaration: void header ( string string [, bool replace [, int http_response_code]])
   The optional replace parameter indicates whether the header should replace a previous similar header, or add a second header of the same type. By default it will replace(true);]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2007/12/16/308.html"  title="Permanet Link to PHP:Header" >http://www.laruence.com/2007/12/16/308.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>     刚在网上看到一个家伙抨击了半天Smarty，ajax，并叫嚣着，凡是写blog的都是菜鸟，高手都是隐隐的，唉，那我这只菜鸟就继续再写点今天整理的一些个东西喽：<br/>
 PHP header()<br/>
   the function declaration: void header ( string string [, bool replace [, int http_response_code]])<br/>
   The optional replace parameter indicates whether the header should replace a previous similar header, or add a second header of the same type. By default it will replace(true);<br/>
  RFC2616有相关的所有的状态信息的说明, 就状态码，大体总结如下：<br/>
   * 1xx: Informational &#8211; Request received, continuing process</p>
<p>　 * 2xx: Success &#8211; The action was successfully received, understood,</p>
<p>　　and accepted</p>
<p>　 * 3xx: Redirection &#8211; Further action must be taken in order to</p>
<p>　　complete the request</p>
<p>　 * 4xx: Client Error &#8211; The request contains bad syntax or cannot be</p>
<p>　　fulfilled</p>
<p>　 * 5xx: Server Error &#8211; The server failed to fulfill an apparently</p>
<p>　　valid request</p>
<p>　　　　　　 | &#8220;100&#8243; ; Continue</p>
<p>　　　　　　 | &#8220;101&#8243; ; Switching Protocols</p>
<p>　　　　　　 | &#8220;200&#8243; ; OK</p>
<p>　　　　　　 | &#8220;201&#8243; ; Created</p>
<p>　　　　　　 | &#8220;202&#8243; ; Accepted</p>
<p>　　　　　　 | &#8220;203&#8243; ; Non-Authoritative Information</p>
<p>　　　　　　 | &#8220;204&#8243; ; No Content</p>
<p>　　　　　　 | &#8220;205&#8243; ; Reset Content</p>
<p>　　　　　　 | &#8220;206&#8243; ; Partial Content</p>
<p>　　　　　　 | &#8220;300&#8243; ; Multiple Choices</p>
<p>　　　　　　 | &#8220;301&#8243; ; Moved Permanently</p>
<p>　　　　　　 | &#8220;302&#8243; ; Moved Temporarily</p>
<p>　　　　　　 | &#8220;303&#8243; ; See Other</p>
<p>　　　　　　 | &#8220;304&#8243; ; Not Modified</p>
<p>　　　　　　 | &#8220;305&#8243; ; Use Proxy</p>
<p>　　　　　　 | &#8220;400&#8243; ; Bad Request</p>
<p>　　　　　　 | &#8220;401&#8243; ; Unauthorized</p>
<p>　　　　　　 | &#8220;402&#8243; ; Payment Required</p>
<p>　　　　　　 | &#8220;403&#8243; ; Forbidden</p>
<p>　　　　　　 | &#8220;404&#8243; ; Not Found</p>
<p>　　　　　　 | &#8220;405&#8243; ; Method Not Allowed</p>
<p>　　　　　　 | &#8220;406&#8243; ; Not Acceptable</p>
<p>　　　　　　 | &#8220;407&#8243; ; Proxy Authentication Required</p>
<p>　　　　　　 | &#8220;408&#8243; ; Request Time-out</p>
<p>　　　　　　 | &#8220;409&#8243; ; Conflict</p>
<p>　　　　　　 | &#8220;410&#8243; ; Gone</p>
<p>　　　　　　 | &#8220;411&#8243; ; Length Required</p>
<p>　　　　　　 | &#8220;412&#8243; ; Precondition Failed</p>
<p>　　　　　　 | &#8220;413&#8243; ; Request Entity Too Large</p>
<p>　　　　　　 | &#8220;414&#8243; ; Request-URI Too Large</p>
<p>　　　　　　 | &#8220;415&#8243; ; Unsupported Media Type</p>
<p>　　　　　　 | &#8220;500&#8243; ; Internal Server Error</p>
<p>　　　　　　 | &#8220;501&#8243; ; Not Implemented</p>
<p>　　　　　　 | &#8220;502&#8243; ; Bad Gateway</p>
<p>　　　　　　 | &#8220;503&#8243; ; Service Unavailable</p>
<p>　　　　　　 | &#8220;504&#8243; ; Gateway Time-out</p>
<p>　　　　　　 | &#8220;505&#8243; ; HTTP Version not supported<br/>
  So， 举几个例子：<br/>
     header(&#8220;HTTP/1.1 404 Not Found&#8221;, true, 404);<br/>
     header(&#8220;HTTP/1.0 401 Unauthorized&#8221;);<br/>
     header(&#8220;Content-Type: text/html; charset=utf-8;&#8221;);<br/>
     header(&#8220;Location:http://www.xxx.com&#8221;);<br/>
  RFC2616 http://www.faqs.org/rfcs/rfc2616</p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2007/12/16/308.html" >2011/04/10</a>, <a href="http://blog.iterse.com"  rel="external nofollow"  class="url" >iterse's blog</a> writes: 谢谢，您的整理与总结！</li><li><a href="http://www.laruence.com/2007/12/16/308.html" >2011/11/29</a>, <a href="http://istrone.com"  rel="external nofollow"  class="url" >istrone</a> writes: 那人有谱儿不，多少反例啊！</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/09/23/539.html"  title="使用PHP Embed SAPI实现Opcodes查看器" >使用PHP Embed SAPI实现Opcodes查看器</a></li><li><a href="http://www.laruence.com/2008/09/19/520.html"  title="深入理解PHP原理之变量分离/引用(Variables Separation)" >深入理解PHP原理之变量分离/引用(Variables Separation)</a></li><li><a href="http://www.laruence.com/2008/08/26/463.html"  title="深入理解PHP原理之变量作用域(Scope in PHP)" >深入理解PHP原理之变量作用域(Scope in PHP)</a></li><li><a href="http://www.laruence.com/2008/08/22/412.html"  title="深入理解PHP原理之变量(Variables inside PHP)" >深入理解PHP原理之变量(Variables inside PHP)</a></li><li><a href="http://www.laruence.com/2008/08/15/274.html"  title="PHP 源代码分析 V0.0.2" >PHP 源代码分析 V0.0.2</a></li><li><a href="http://www.laruence.com/2008/08/14/250.html"  title="实现PHP的编译执行分离(separating compilation and execution)" >实现PHP的编译执行分离(separating compilation and execution)</a></li><li><a href="http://www.laruence.com/2008/08/12/180.html"  title="深入理解Zend SAPIs(Zend SAPI Internals)" >深入理解Zend SAPIs(Zend SAPI Internals)</a></li><li><a href="http://www.laruence.com/2008/08/12/164.html"  title="深入理解PHP原理之函数(Introspecting PHP Function)" >深入理解PHP原理之函数(Introspecting PHP Function)</a></li><li><a href="http://www.laruence.com/2008/08/11/147.html"  title="深入浅出PHP(Exploring PHP)" >深入浅出PHP(Exploring PHP)</a></li><li><a href="http://www.laruence.com/2008/06/18/221.html"  title="深入理解PHP原理之Opcodes" >深入理解PHP原理之Opcodes</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2007/12/16/308.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

