<?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; bug</title>
	<atom:link href="http://www.laruence.com/tag/bug/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 Reflection Extension的一个bug</title>
		<link>http://www.laruence.com/2011/03/22/1929.html</link>
		<comments>http://www.laruence.com/2011/03/22/1929.html#comments</comments>
		<pubDate>Tue, 22 Mar 2011 12:47:53 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[reflection]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1929</guid>
		<description><![CDATA[今天同事<a href="http://eddix.blogbus.com/">eddix</a>告诉我发现一个PHP的warning, 

<coolcode lang="php" linenum="off">
$php --re dummy
Warning: Internal error: Cannot find extension function Dummy 
in global function table in Unknown on line 0
</coolcode>
 
   以前没有遇到过, 不知道什么意思.]]></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/2011/03/22/1929.html"  title="Permanet Link to PHP Reflection Extension的一个bug" >http://www.laruence.com/2011/03/22/1929.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   今天同事<a href="http://eddix.blogbus.com/" >eddix</a>告诉我发现一个PHP的warning, </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 --re dummy
Warning: Internal error: Cannot find extension function Dummy
in global function table in Unknown on line 0
</pre>
<p>   以前没有遇到过, 不知道什么意思.</p>
<p>   经过翻看代码, 发现了一个reflection extension的Bug:</p>
<p>   同事自己写的扩展中, 在module entry中注册的function table里的funcion是大小写的, 类似于上面出错信息中的Dummy,<br/>
而我们都知道, PHP的function_table中的函数都是小写的(参看我之前的文章<a href="http://www.laruence.com/2008/08/12/164.html" >深入理解PHP原理之函数(Introspecting PHP Function)</a>).</p>
<p>   于是reflection extension的如下这段代码就会报错:</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;">
 if (module-&gt;functions &amp;&amp; module-&gt;functions-&gt;fname) {
        //有省略
        while (func-&gt;fname) {
            if (zend_hash_find(EG(function_table),
                //注意这里, 没有小写化函数名.
                func-&gt;fname, strlen(func-&gt;fname) + 1, (void**) &amp;fptr) == FAILURE) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING,
                      &quot;Internal error: Cannot find extension function %
                      in global function table&quot;, func-&gt;fname);
                func++;
                continue;
            }
    //有省略
    }
</pre>
<p>    注意看, 在EG(function_table)中查找的时候, 并没有小写化func->fname, 就导致找不到了..</p>
<p>    呵呵, 小bug, 已经report了: <a href="http://bugs.php.net/bug.php?id=54347" >http://bugs.php.net/bug.php?id=54347</a><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/2011/03/22/1929.html" >2011/03/22</a>, fy writes: 'PHP的function_table中的函数都是小写的' ，是不是这么理解：算是约定，只能自定义小写函数名，所以不是bug？：）</li><li><a href="http://www.laruence.com/2011/03/22/1929.html" >2011/03/23</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @fy 你说的也有道理哈,嘿嘿</li><li><a href="http://www.laruence.com/2011/03/22/1929.html" >2011/03/23</a>, cataphrac writes: This should still probably be fixed, but the functions should be declared with lowercase names. If you search for PHP_FE in lxr.php.net, you'll notice this is always the case.

In any case, since zend_register_functions does a lowercasing of the function names in the module list, the reflection ext should do it too. But for forward compatibility (in the future we may want to reduce the points where names are lowercased), it would be best if the extension follows the convention.</li><li><a href="http://www.laruence.com/2011/03/22/1929.html" >2011/03/23</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @cataphrac I can't agree with you more~</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/11/27/1164.html"  rel="bookmark"  title="Permanent Link: memory_limit的一个bug" >memory_limit的一个bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  rel="bookmark"  title="Permanent Link: PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li><li><a href="http://www.laruence.com/2009/08/18/1042.html"  rel="bookmark"  title="Permanent Link: 保证PHP扩展的依赖关系" >保证PHP扩展的依赖关系</a></li><li><a href="http://www.laruence.com/2011/05/12/2009.html"  rel="bookmark"  title="Permanent Link: Yaf-A PHP Framework Extension" >Yaf-A PHP Framework Extension</a></li><li><a href="http://www.laruence.com/2009/06/14/945.html"  rel="bookmark"  title="Permanent Link: 深入理解PHP原理之扩展载入过程" >深入理解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/2010/05/28/1565.html"  title="PHP错误抑制符(@)导致引用传参失败的Bug" >PHP错误抑制符(@)导致引用传参失败的Bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  title="PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html"  title="PHP5.2.x + APC的一个bug的定位" >PHP5.2.x + APC的一个bug的定位</a></li><li><a href="http://www.laruence.com/2008/08/24/427.html"  title="PHP5多层继承顺序的bug" >PHP5多层继承顺序的bug</a></li><li><a href="http://www.laruence.com/2012/02/08/2528.html"  title="PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)" >PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)</a></li><li><a href="http://www.laruence.com/2012/02/02/2515.html"  title="我们什么时候应该使用异常?" >我们什么时候应该使用异常?</a></li><li><a href="http://www.laruence.com/2012/02/01/2503.html"  title="使用exit(-1)为什么得到255退出码?" >使用exit(-1)为什么得到255退出码?</a></li><li><a href="http://www.laruence.com/2012/01/11/2482.html"  title="PHP的历史" >PHP的历史</a></li><li><a href="http://www.laruence.com/2012/01/10/2469.html"  title="如何设置一个严格30分钟过期的Session" >如何设置一个严格30分钟过期的Session</a></li><li><a href="http://www.laruence.com/2012/01/07/2453.html"  title="2012年1月全球www网站技术报告" >2012年1月全球www网站技术报告</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2011/03/22/1929.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>PHP错误抑制符(@)导致引用传参失败的Bug</title>
		<link>http://www.laruence.com/2010/05/28/1565.html</link>
		<comments>http://www.laruence.com/2010/05/28/1565.html#comments</comments>
		<pubDate>Fri, 28 May 2010 14:27:58 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[@]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[refer]]></category>
		<category><![CDATA[send_ref]]></category>
		<category><![CDATA[send_var_no_ref]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1565</guid>
		<description><![CDATA[今天cici网友发来一个问题, 说是在函数调用参数前面使用错误抑制符号(@)的时候, 貌似引用传参就失效了. 他想让我帮他解答为什么.

     看下面的例子:
<coolcode lang="php" linenum="off">
.....
</coolcode>

  这个问题, 我之前没有遇到过, 所以首先去找找相关资料, 看看有没有现成的答案, Goolge了一番, 发现虽然有人已经向PHP报了类似的Bug:<a href="http://bugs.php.net/bug.php?id=47623" target="_blank">http://bugs.php.net/bug.php?id=47623</a>, 但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/2010/05/28/1565.html"  title="Permanet Link to PHP错误抑制符(@)导致引用传参失败的Bug" >http://www.laruence.com/2010/05/28/1565.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>
     今天cici网友发来一个问题, 说是在函数调用参数前面使用错误抑制符号(@)的时候, 貌似引用传参就失效了. 他想让我帮他解答为什么.</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
$array = array(1,2,3);

function add (&amp;$arr) {
    $arr[] = 4;
}
add(@$array);
print_r($array);
/**
此时, $array没有改变,　输出:
Array
(
    [0] =&gt; 1
    [1] =&gt; 2
    [2] =&gt; 3
)

*/
add($array);
print_r($array);
/**
不使用错误抑制的情况下, 输出正常:
Array
(
    [0] =&gt; 1
    [1] =&gt; 2
    [2] =&gt; 3
    [3] =&gt; 4
)
*/
?&gt;
</pre>
<p>  这个问题, 我之前没有遇到过, 所以首先去找找相关资料, 看看有没有现成的答案, Goolge了一番, 发现虽然有人已经向PHP报了类似的Bug:<a href="http://bugs.php.net/bug.php?id=47623"  target="_blank" >http://bugs.php.net/bug.php?id=47623</a>, 但PHP官方还没有解决, 也没有给出答复.</p>
<p>   没办法, 只能自己分析了, 之前我曾经在文章中介绍过错误抑制符的原理(<a href="http://www.laruence.com/2009/07/27/1020.html" > 深入理解PHP原理之错误抑制与内嵌HTML</a>), 从原理上来说, 错误抑制只是修改了error_reporting的level, 按理来说不会影响到上下文之间的函数调用的机制. 只能通过实地试验了.</p>
<p>   经过gdb跟踪, 发现在使用了错误移植符以后, 函数调用前的传参opcode不同:</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;">
//没有使用错误抑制符的时候
OPCODE = SEND_REF 

//使用了错误抑制符号以后
OPCODE = SEND_VAR_NO_REF
</pre>
<p>   问题初步定位了, 但是造成这种差异的原因又是什么呢?</p>
<p>   既然OPCODE不同, 那么肯定是在语法分析的阶段, 走了不同的分支了, 想到这一层, 问题也就好定位了, </p>
<p>   原来, PHP语法分析阶段, 把形如 &#8220;@&#8221;+expr的条目, 规约成了expr_without_variable, 而这种节点的意义就是没有变量的值, 也就是字面值, 我们都知道字面值是不能传递引用的(因为它不是变量), 所以, 就会导致这种差异.</p>
<p>  具体过程如下:<br/>
1.  语法分析阶段:</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;">
expr_without_variable:
//...有省略
   |   '@' { zend_do_begin_silence(&amp;$1 TSRMLS_CC); }
       expr { zend_do_end_silence(&amp;$1 TSRMLS_CC); $$ = $3; }

//此处走了ZEND_SEND_VAL分支
non_empty_function_call_parameter_list:
        expr_without_variable   { ....} //错误的走了这个分支
    |   variable                {..... } //正常情况下
</pre>
<p>   所以导致在编译期间, 生成了不同的OPCODE, 也导致了问题的表象. </p>
<p>   最后, 我已经把原因在PHP的这个bug页做了说明, 有兴趣的可以去看看我的烂英语水平.  最后谢谢cici网友提供的这个有趣的问题.<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></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/2010/05/28/1565.html" >2010/05/29</a>, <a href="http://www.jaceju.net/blog/?p=1196"  rel="external nofollow"  class="url" >網站製作學習誌 &raquo; [Web] 連結分享</a> writes: [...] PHP錯誤抑制符(@)導致引用傳參失敗的Bug [...]</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2010/06/01</a>, 小熊 writes: 长知识了，劳伦斯大叔威武</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2010/06/10</a>, <a href="http://www.sjade.com"  rel="external nofollow"  class="url" >互联生活网</a> writes: 长知识了，</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2010/07/30</a>, <a href="http://www.commentset.com"  rel="external nofollow"  class="url" >mahone</a> writes: 错误抑制符是这样用的？add(@$array);
不是用在函数前面的么？@add($array);
望求教</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2010/07/30</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @mahone 有的时候, 我们引用一个数组的元素的时候, 这个数组元素可能不存在, 我们为了避免它notice, 就会采用 func(@$array['key']);</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2010/07/30</a>, <a href="http://www.commentset.com"  rel="external nofollow"  class="url" >mahone</a> writes: @雪候鸟
这样的啊，那isset这样判断下不好么？
如果不判断穿进去，那是去函数里面判断了是吧 ？</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2010/09/28</a>, 过客 writes: 大哥,我们之前没有C的开发经验，但也想了解一下PHP的源码。能否把这个例子整个gdb的追踪步骤都写出来呀？谢谢</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=150"  rel="external nofollow"  class="url" >PHP错误抑制符(@)导致引用传参失败的Bug | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2010/05/28/1565.html [...]</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2011/03/30</a>, <a href="http://www.laruence.com/2011/03/24/858.html"  rel="external nofollow"  class="url" >一些PHP Coding Tips[2011/03/30最后更新] | 风雪之隅</a> writes: [...] func(); error_reporting($report); 另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug);最后,错误抑制符在发生错误调试的时候也可能会带来麻烦. 12. [...]</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2011/04/15</a>, <a href="http://www.seo4it.com/archives/php-coding-tips"  rel="external nofollow"  class="url" >PHP Coding Tips | SEO 4 IT - Website Creater</a> writes: [...] 另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug); [...]</li><li><a href="http://www.laruence.com/2010/05/28/1565.html" >2011/04/19</a>, <a href="http://honeybear.me/2011/04/php-coding-tips/"  rel="external nofollow"  class="url" >PHP Coding Tips | 蜂蜜小熊的家</a> writes: [...] 另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug); [...]</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/2010/09/27/1754.html"  rel="bookmark"  title="Permanent Link: PHP stream未能及时清理现场导致Core的bug" >PHP stream未能及时清理现场导致Core的bug</a></li><li><a href="http://www.laruence.com/2008/08/24/427.html"  rel="bookmark"  title="Permanent Link: PHP5多层继承顺序的bug" >PHP5多层继承顺序的bug</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/2011/03/22/1929.html"  title="PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  title="PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html"  title="PHP5.2.x + APC的一个bug的定位" >PHP5.2.x + APC的一个bug的定位</a></li><li><a href="http://www.laruence.com/2008/08/24/427.html"  title="PHP5多层继承顺序的bug" >PHP5多层继承顺序的bug</a></li><li><a href="http://www.laruence.com/2012/02/08/2528.html"  title="PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)" >PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)</a></li><li><a href="http://www.laruence.com/2012/02/02/2515.html"  title="我们什么时候应该使用异常?" >我们什么时候应该使用异常?</a></li><li><a href="http://www.laruence.com/2012/02/01/2503.html"  title="使用exit(-1)为什么得到255退出码?" >使用exit(-1)为什么得到255退出码?</a></li><li><a href="http://www.laruence.com/2012/01/11/2482.html"  title="PHP的历史" >PHP的历史</a></li><li><a href="http://www.laruence.com/2012/01/10/2469.html"  title="如何设置一个严格30分钟过期的Session" >如何设置一个严格30分钟过期的Session</a></li><li><a href="http://www.laruence.com/2012/01/07/2453.html"  title="2012年1月全球www网站技术报告" >2012年1月全球www网站技术报告</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/05/28/1565.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>PHP类型转换相关的一个Bug</title>
		<link>http://www.laruence.com/2010/05/26/1541.html</link>
		<comments>http://www.laruence.com/2010/05/26/1541.html#comments</comments>
		<pubDate>Wed, 26 May 2010 06:45:15 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php源码分析]]></category>
		<category><![CDATA[type cast]]></category>
		<category><![CDATA[类型转换]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1541</guid>
		<description><![CDATA[ PHP为了避免数字索引和数字字符串索引(注1)的混乱, 引入了zend_symtable_*系列函数, 并应用于数组中.
  
   这样一来, 数字字符串索引也就会被当作数字索引, 然而总是有一些情况, 是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/2010/05/26/1541.html"  title="Permanet Link to PHP类型转换相关的一个Bug" >http://www.laruence.com/2010/05/26/1541.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   PHP为了避免数字索引和数字字符串索引(注1)的混乱, 引入了zend_symtable_*系列函数, 并应用于数组中.</p>
<p>   这样一来, 数字字符串索引也就会被当作数字索引, 然而总是有一些情况, 是PHP的维护者没有想到的&#8230;</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;">
鉴于很多朋友好心的提示, 使用json_deocde的第二个参数就可以直接得到数组.
我说明下, 如下的代码是我有意而为之, 并不是为了json_decode, 而是为了构造一个&quot;有问题&quot;的数组.
</pre>
<p> 在PHP5.2.*下(json version	1.2.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;">

$data = array(
    123 =&gt; 'laruence',
);

$value = json_encode($data);
$obj   = json_decode($value);
$arr   = (array)$obj;
var_dump($arr);
</pre>
<p>   另<a href="http://syre.blogbus.com/"  target="_blank" >神仙</a>提供了如下的更简单的构造方法:</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;">
$obj=new stdClass;
$obj-&gt;{'123'} = &quot;laruence&quot;;
$arr = (array)$obj;
var_dump($arr);
</pre>
<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;">
array(1) {
  [&quot;123&quot;]=&gt;
  string(8) &quot;laruence&quot;
}
</pre>
<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;">
print_r($arr[123]);
//PHP Notice:  Undefined offset:  123 in ***
print_r($arr[&quot;123&quot;]);
//PHP Notice:  Undefined offset:  123 in ***
var_dump(array_key_exists(&quot;123&quot;, $arr));
//bool(false)
</pre>
<p>  我已经报了Bug, 不过PHP本身也不保证类型转换的一致性, 所以PHP维护者最后认为是不是Bug都无所谓了, 大家平时注意即可:<a href="http://bugs.php.net/bug.php?id=51915"  target="_blank" >http://bugs.php.net/bug.php?id=51915</a> </p>
<p><b>注1</b></p>
<p> 本文中所说的字符串数字和之前的文章<a href="http://www.laruence.com/2009/02/21/662.html"  target="_blank" >PHP字符串比较</a>中所说的numeric string有一点不同, 在zend_symtable_*系列函数中, 只会吧/^-?[^0][0-9]*$/这样的字符串认为是数字字符串. 相关核心逻辑如下:</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 HANDLE_NUMERIC(key, length, func) {
    register char *tmp=key;
    if (*tmp=='-') {
        tmp++;
    }
    if ((*tmp&gt;='0' &amp;&amp; *tmp&lt;='9')) do {
        char *end=key+length-1;
        long idx;
        if (*tmp++=='0' &amp;&amp; length&gt;2) {
            break;
        }
        while (tmp&lt;end) {
            if (!(*tmp&gt;='0' &amp;&amp; *tmp&lt;='9')) {
                break;
            }
            tmp++;
        }
        if (tmp==end &amp;&amp; *tmp=='0') {
            if (*key=='-') {
                idx = strtol(key, NULL, 10);
                if (idx!=LONG_MIN) {
                    return func;
                }
            } else {
                idx = strtol(key, NULL, 10);
                if (idx!=LONG_MAX) {
                    return func;
                }
            }
        }
    } while (0);
}
</pre>
<p>  <b>PS</b>:我这里只有5.2.8, 5.2.11俩个版本, 各位读者如果有其他版本的PHP, 帮忙测试下是否在你的版本下也存在这个问题. 谢谢</p>
<p>  另: 谢谢<a href="http://www.cppblog.com/qywyh"  target="_blank" >远豪</a>提供这个问题, 原问题是和Memcached相关的.<br/>
<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_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_c.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/2010/05/26/1541.html" >2010/05/26</a>, <a href="http://skiyo.cn"  rel="external nofollow"  class="url" >Jessica</a> writes: 鸟哥 decode的时候多价格参数 不要返回object 直接返回成数组..

$arr = json_decode($value, true)</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/05/26</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @jessica 我是处心积虑的特意这么做的,为了构造这么个数组, 呵呵</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/05/26</a>, <a href="http://skiyo.cn"  rel="external nofollow"  class="url" >Jessica</a> writes: 是我误会鸟哥了..汗</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/05/26</a>, <a href="http://micy.cn/blog/"  rel="external nofollow"  class="url" >bunnyq</a> writes: 5.3.2下也是这个结果</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/05/26</a>, .... writes: $data = array(
    123 =&gt; 'laruence',
);
var_dump($data);

这时候就打印不出来了，还需要转换么？</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/05/26</a>, <a href="http://blog.imxifs.info"  rel="external nofollow"  class="url" >xifs</a> writes: 5.3.2也如此</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/05/26</a>, noknow writes: 多看手册没坏处的！</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/06/07</a>, <a href="http://syre.blogbus.com"  rel="external nofollow"  class="url" >神仙</a> writes: 有个更简单的构造办法
$obj=new stdClass;
$obj-&gt;{'123'} = 1;
$arr = (array)$obj;
var_dump($arr);</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/06/07</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @神仙 赞, 我还真没想到能这么做. ;)</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/06/10</a>, <a href="http://www.mmyuqi.com"  rel="external nofollow"  class="url" >两性解答</a> writes: 还需要转换么？</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2010/06/26</a>, <a href="http://%/zzdwsyg1"  rel="external nofollow"  class="url" >BILLY</a> writes: <strong>PillSpot.org. Canadian Health&amp;Care.Special Internet Prices.No prescription online pharmacy.Pillspot.org.<b> <a href="http://pillspot.org/products/vitamins_herbal_supplements/ Vitamins@buy.online"  rel="nofollow" >.</a>...</strong>

Categories: <b>Stop SmokingMental HealthVitamins/Herbal Supplements.Anxiety/Sleep Aid.Antidiabetic.Eye Care.Antiviral.Antibiotics.Stomach.Blood Pressure/Heart.Antidepressants.Pain Relief.Womens Health.Anti-allergic/Asthma.Skin Care.Mens Health.Weight...</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2011/03/11</a>, k writes: json_encode的实现里面，判断一个数组是索引数组还是关联数组，认为索引数组必须从0开始，所以非0开始的数组都当做是关联数组，关联数组的键就当做字符串处理了。</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=148"  rel="external nofollow"  class="url" >PHP类型转换相关的一个Bug | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2010/05/26/1541.html [...]</li><li><a href="http://www.laruence.com/2010/05/26/1541.html" >2011/11/02</a>, 何林丹 writes: 我的是5.2.10,也出现同样的bug.我又测试了下object转换成array,也是同样的问题。
希望有时间能给大家讲些php强制转换的原理
 'laruence',
             );
$obj = (object)$data;
var_dump($obj);
var_dump($obj-&gt;{123});
//NULL
?&gt;</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/11/27/1164.html"  rel="bookmark"  title="Permanent Link: memory_limit的一个bug" >memory_limit的一个bug</a></li><li><a href="http://www.laruence.com/2011/03/22/1929.html"  rel="bookmark"  title="Permanent Link: PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html"  rel="bookmark"  title="Permanent Link: PHP5.2.x + APC的一个bug的定位" >PHP5.2.x + APC的一个bug的定位</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/2011/03/22/1929.html"  title="PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2011/03/04/1894.html"  title="深入理解PHP内存管理之谁动了我的内存" >深入理解PHP内存管理之谁动了我的内存</a></li><li><a href="http://www.laruence.com/2010/05/28/1565.html"  title="PHP错误抑制符(@)导致引用传参失败的Bug" >PHP错误抑制符(@)导致引用传参失败的Bug</a></li><li><a href="http://www.laruence.com/2010/05/20/1495.html"  title="Nginx + PHP CGI的一个可能的安全漏洞" >Nginx + PHP CGI的一个可能的安全漏洞</a></li><li><a href="http://www.laruence.com/2010/05/18/1482.html"  title="深入理解PHP原理之对象(一)" >深入理解PHP原理之对象(一)</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html"  title="PHP5.2.x + APC的一个bug的定位" >PHP5.2.x + APC的一个bug的定位</a></li><li><a href="http://www.laruence.com/2009/11/27/1164.html"  title="memory_limit的一个bug" >memory_limit的一个bug</a></li><li><a href="http://www.laruence.com/2009/10/15/1131.html"  title="提升PHP性能之改变Zend引擎分发方式" >提升PHP性能之改变Zend引擎分发方式</a></li><li><a href="http://www.laruence.com/2009/09/26/1103.html"  title="PHP文件上传源码分析(RFC1867)" >PHP文件上传源码分析(RFC1867)</a></li><li><a href="http://www.laruence.com/2009/07/27/1020.html"  title="深入理解PHP原理之错误抑制与内嵌HTML" >深入理解PHP原理之错误抑制与内嵌HTML</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/05/26/1541.html/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>PHP5.2.x + APC的一个bug的定位</title>
		<link>http://www.laruence.com/2009/12/05/1172.html</link>
		<comments>http://www.laruence.com/2009/12/05/1172.html#comments</comments>
		<pubDate>Sat, 05 Dec 2009 07:39:24 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[core]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php bug]]></category>
		<category><![CDATA[session]]></category>
		<category><![CDATA[spl_autoload]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1172</guid>
		<description><![CDATA[昨天环境迁移, 脚本出core, 因为之前的环境上运行正常, 所以初步认为是环境问题. 通过对core文件的分析, 初步发现原因和spl_autoload相关, backtrace如下:
<coolcode lang="bash" linenum="off">
#0  zif_spl_autoload (ht=Variable "ht" is not available.)
at /home/huixinchen/package/php-5.2.11/ext/spl/php_spl.c:310
310   if (active_opline->opcode != ZEND_FETCH_CLASS) {

(gdb) bt
#0  zif_spl_autoload (ht=Variable "ht" is not available.
	) at /home/huixinchen/package/php-5.2.11/ext/spl/php_spl.c:310
#1  0x00000000006a5da5 in zend_call_function (fci=0x7fbfffc100, 
		fci_cache=Variable "fci_cache" is not available.)
at /home/huixinchen/package/php-5.2.11/Zend/zend_execute_API.c:1052
.....
</coolcode>
脚本很简单, 通过session_set_save_handler注册了一个类为session的user handler.

去掉spl_autoload以后,  不出core了, 但是每次都会抛出Class not found的异常, 可见core确实和spl_autoload有关, 但是这个Class ** not found的fatal error问题又和什么相关呢, 这个fatal error是否是导致spl_autoload core 的直接原因呢?

代码本身并没有任何问题, 对环境做了对比以后, 初步认定为新环境启用了APC的缘故.

在bug.php中找到了有人报告类似的bug(<a href="http://bugs.php.net/bug.php?id=49867&#038;edit=2" target="_blank">spl_autoload crashes when called in write function of custom sessionSaveHandler</a>), 但没有任何一个人给出原因,或者解决的办法. 

看来, 只能自己分析了....]]></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/2009/12/05/1172.html"  title="Permanet Link to PHP5.2.x + APC的一个bug的定位" >http://www.laruence.com/2009/12/05/1172.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>
昨天环境迁移, 脚本出core, 因为之前的环境上运行正常, 所以初步认为是环境问题. 通过对core文件的分析, 初步发现原因和spl_autoload相关, backtrace如下:</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;">
#0  zif_spl_autoload (ht=Variable &quot;ht&quot; is not available.)
at /home/huixinchen/package/php-5.2.11/ext/spl/php_spl.c:310
310   if (active_opline-&gt;opcode != ZEND_FETCH_CLASS) {

(gdb) bt
#0  zif_spl_autoload (ht=Variable &quot;ht&quot; is not available.
	) at /home/huixinchen/package/php-5.2.11/ext/spl/php_spl.c:310
#1  0x00000000006a5da5 in zend_call_function (fci=0x7fbfffc100,
		fci_cache=Variable &quot;fci_cache&quot; is not available.)
at /home/huixinchen/package/php-5.2.11/Zend/zend_execute_API.c:1052
.....
</pre>
<p>脚本很简单, 通过session_set_save_handler注册了一个类为session的user handler.</p>
<p>去掉spl_autoload以后,  不出core了, 但是每次都会抛出Class not found的异常, 可见core确实和spl_autoload有关, 但是这个Class ** not found的fatal error问题又和什么相关呢, 这个fatal error是否是导致spl_autoload core 的直接原因呢?</p>
<p>代码本身并没有任何问题, 对环境做了对比以后, 初步认定为新环境启用了APC的缘故.</p>
<p>在bug.php中找到了有人报告类似的bug(<a href="http://bugs.php.net/bug.php?id=49867&#038;edit=2"  target="_blank" >spl_autoload crashes when called in write function of custom sessionSaveHandler</a>), 但没有任何一个人给出原因,或者解决的办法. </p>
<p>看来, 只能自己分析了&#8230;.
</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
/**
 * PHP5.2.11 with APC Fatal Error example
 * by laruence(http://www.laruence.com)
 */
class Laruence {
	public static function start() {
		session_set_save_handler(array(__CLASS__, &quot;open&quot;),
				array(__CLASS__, &quot;close&quot;), array(__CLASS__, &quot;read&quot;),
				array(__CLASS__, &quot;write&quot;), array(__CLASS__, &quot;destroy&quot;),
				array(__CLASS__, &quot;gc&quot;));
		session_start();
	}
	public static function open($strPath, $strSessName) {
		return true;
	}
	public static function close() {
		var_dump(class_exists(__CLASS__, false));
	}
	public static function read($strSessId) {
	}
	public static function write($strSessId, $strData) {
	}
	public static function destroy($strSessId) {
	}
	public static function gc($intMaxLifeTime) {
		return true;
	}
}
Laruence::start();
?&gt;
</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;">
PHP Fatal error:  Class 'Laruence' not found in Unknown on line 0
</pre>
<p>可见, 这个原因一定是和APC缓存了脚本编译结果以后有关.</p>
<p>翻看APC的源码, 发现了一处可怀疑之处, apc_main.c中:</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;">
static void apc_deactivate(TSRMLS_D) //此函数在请求关闭期间被调用
{
while (apc_stack_size(APCG(cache_stack)) &gt; 0) {
...//有省略
	if (cache_entry-&gt;data.file.classes) {
		for (i = 0; cache_entry-&gt;data.file.classes[i].class_entry != NULL; i++) {
			if(zend_hash_find(EG(class_table),
					cache_entry-&gt;data.file.classes[i].name,
					cache_entry-&gt;data.file.classes[i].name_len+1,
					(void**)centry) == FAILURE) {
						continue;
			}
			//注意这里:
			zend_hash_del(EG(class_table),
					cache_entry-&gt;data.file.classes[i].name,
					cache_entry-&gt;data.file.classes[i].name_len+1);
			apc_free_class_entry_after_execution(zce);
		}
	}

	...//有省略
}
}
</pre>
<p>也就是说, APC在模块请求关闭函数时期, 清空了执行全局标量中的类定义表EG(classs_table), 根据我的经验, 问题可能就在这里.</p>
<p>经过反复验证: 改hanlder,  跟踪源码, gdb,, 最后问题定位确定, 确实就是这个原因(对不住女朋友了, 搞到半夜快2点才最终确定问题):</p>
<p>恩, 我之前的文章介绍过PHP的扩展载入过程(<a href="http://www.laruence.com/2009/06/14/945.html"  target="_blank" >深入理解PHP原理之扩展载入过程</a>), 但没有涉及到模块关闭过程.</p>
<p>而这个问题就和模块载入顺序和模块关闭函数很有关系了. 总体来说, 就是PHP会根据模块载入的顺序的反序来在每次请求处理结束后依次调用各个扩展的请求关闭函数.</p>
<p>因为我们环境的Session是静态编译进PHP的, 所以Session模块一定先于动态编译进PHP的APC被载入, 也就是说, 在请求关闭时期, APC的请求关闭函数, 一定会先于Session的请求关闭函数被调用.</p>
<p>所以,当Session的请求关闭函数调用的时候, 执行环境的Class Table已经为空, 当然也就会抛出类找不到的fatalerror了.</p>
<p>而, 第一次请求的时候, 因为页面没有被缓存, 所以apc_stack_size(APCG(cache_stack))的条件判断不成立, 也就不会有清除class table的动作发生.</p>
<p>基于此, 为什么在spl_autoload启用以后, 产生core, 也就很明显了.</p>
<p>因为在zif_spl_autoload中, 对active_opline接引用, 而此时执行已经结束, active_opline为空, 所以,segment fault了.</p>
<p>那么, 如何解决这个问题呢?</p>
<pre name="code"  class="sh_sh"  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. 关闭APC //废话,我也知道, 呵呵
2. 改用函数做为session_set_save_handler的user handler.
3. 把seesion模块做为动态模块载入PHP, 并保证它后于APC被载入. //这个解决方法靠谱.
</pre>
<p>关于APC的执行原理, 大家如果有兴趣, 我过段再单独写篇blog.</p>
<p>最后, APC是好, 但一致没有被做为PHP的标准扩展, 也是有原因的. 它劫持了PHP自身的complie_file, 加入了很多局部性很强的逻辑&#8230;</p>
<p>一句话, APC虽好, 但须慎用.</p>
<p><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_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_sh.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/2009/12/05/1172.html" >2009/12/06</a>, 玉丰 writes: 最近也在折腾gdb，看了一下这篇文章，（还不会如何去backtrace PHP的运行），呵呵，继续学习。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2009/12/07</a>, <a href="www.phppan.com"  rel="external nofollow"  class="url" >phppan</a> writes: 围观，学习！</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2009/12/16</a>, kimjxie writes: 在代码末 强制执行session_write_close()也可解决问题</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2009/12/17</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @kimjxie 赞~, 这是提前了关闭的时机. 这个bug还是依然值得探讨的. ;)</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/01/15</a>, <a href="http://www.baidu.com"  rel="external nofollow"  class="url" >wakaka</a> writes: 博主的PHP和C的功力实在是国内少有的高手。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/03/19</a>, luckgo writes: 老兄，我遇到类似问题，但无法解决。
我在windows下装了php_apc.dll后，访问phpMyAdmin（版本3.1.3）出现错误：
Warning: require_once(D:\apache\libraries\common.inc.php) [function.require-once]: failed to open stream: No such file or directory in E:\phpweb\phpMyAdmin3\index.php  on line 34

在使用zend framework框架时，出现
class XXX not found的错误，很奇怪，似乎与session没什么关系，请问有没办法解决？</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/03/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @luckgo 文件不存在那么..</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/07/28</a>, abagail writes: Zenith Watches Company is a Swiss company that has <a href="http://www.sanwatches.com/cartier-watches.html"  rel="nofollow" >cartier fake watches</a> breitling chronomat evolution straps have the advantage of being made from a <a href="http://www.sanwatches.com/a_lange_and_sohne-watches.html"  rel="nofollow" >replica a lange and sohne watch</a> automatic watches far from what they like or would buy for <a href="http://www.watchesfaner.com/swiss_rolex-watches.html"  rel="nofollow" >swiss replica</a> assioma watches available on the new RSW High King Tourbillon <a href="http://www.watchesfaner.com/ladies_watches.html"  rel="nofollow" >buy watches</a> omega olympic collection watches enhanced and the promotional lights create an <a href="http://www.corwatches.org/"  rel="nofollow" >replica watches</a> retailers to see what products have arrived in <a href="http://www.corwatches.org/rolex-milgauss-watches.html"  rel="nofollow" >rolex milgauss watches</a> arrives with a long lasting brass situation Other <a href="http://www.sanwatches.com/tag_heuer-watches.html"  rel="nofollow" >tag heuer fake</a> heard about Gucci They are one of the largest <a href="http://www.sanwatches.com/"  rel="nofollow" >fake watch</a> that updated to make it more suitable to the <a href="http://www.pocwatches.com/"  rel="nofollow" >replica watch</a> out with various styles celebrating this trip to <a href="http://www.sanwatches.com/"  rel="nofollow" >watches replica</a> baguette cut diamonds and baguette cut rubies <a href="http://www.sanwatches.com/breitling-watches.html"  rel="nofollow" >breitling fake watches</a> libre watches a team of visionary designers and specialists of <a href="http://www.watchesfaner.com/omega-watches.html"  rel="nofollow" >replica omega</a> under their French cuff shirts and hence they can</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/08/19</a>, <a href="http://www.watchfordream.com"  rel="external nofollow"  class="url" >Watchfordream</a> writes: Wonderful!
<a href="http://wwww.watchfordream.com"  rel="nofollow" >swiss replica watches</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2011/01/20</a>, <a href="http://zhg.me"  rel="external nofollow"  class="url" >hfcorriez</a> writes: 受教了。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=172"  rel="external nofollow"  class="url" >PHP5.2.x + APC的一个bug的定位 | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2009/12/05/1172.html [...]</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2011/09/26</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/2009/12/05/1172.html" >2011/12/06</a>, hfcorriez writes: 以前也发现过这个问题，苦于自己没法定位放弃APC了。今天终于知道原因了。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2012/01/12</a>, 偷蚊子的 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/11/27/1164.html"  rel="bookmark"  title="Permanent Link: memory_limit的一个bug" >memory_limit的一个bug</a></li><li><a href="http://www.laruence.com/2011/03/22/1929.html"  rel="bookmark"  title="Permanent Link: PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  rel="bookmark"  title="Permanent Link: PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</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/2012/01/10/2469.html"  title="如何设置一个严格30分钟过期的Session" >如何设置一个严格30分钟过期的Session</a></li><li><a href="http://www.laruence.com/2011/12/06/2381.html"  title="更简单的重现PHP Core的调用栈" >更简单的重现PHP Core的调用栈</a></li><li><a href="http://www.laruence.com/2011/10/10/2217.html"  title="上传进度支持(Upload progress in sessions)" >上传进度支持(Upload progress in sessions)</a></li><li><a href="http://www.laruence.com/2011/06/23/2057.html"  title="如何调试PHP的Core之获取基本信息" >如何调试PHP的Core之获取基本信息</a></li><li><a href="http://www.laruence.com/2011/03/29/1949.html"  title="深入理解PHP原理之Session Gc的一个小概率Notice" >深入理解PHP原理之Session Gc的一个小概率Notice</a></li><li><a href="http://www.laruence.com/2011/03/22/1929.html"  title="PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2011/01/27/1854.html"  title="深入理解PHP内存管理之一个低概率Core的分析" >深入理解PHP内存管理之一个低概率Core的分析</a></li><li><a href="http://www.laruence.com/2010/09/27/1754.html"  title="PHP stream未能及时清理现场导致Core的bug" >PHP stream未能及时清理现场导致Core的bug</a></li><li><a href="http://www.laruence.com/2010/05/28/1565.html"  title="PHP错误抑制符(@)导致引用传参失败的Bug" >PHP错误抑制符(@)导致引用传参失败的Bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  title="PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/12/05/1172.html/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>PHP5多层继承顺序的bug</title>
		<link>http://www.laruence.com/2008/08/24/427.html</link>
		<comments>http://www.laruence.com/2008/08/24/427.html#comments</comments>
		<pubDate>Sun, 24 Aug 2008 13:43:57 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[Linux/Unix]]></category>
		<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[class]]></category>
		<category><![CDATA[extends]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=427</guid>
		<description><![CDATA[<p>今天guoxiaod提出了一个问题，如下：
  <coolcode lang="php" linenum="off">
<?php
class a extends b {
};
class b extends c{
};
class c{
};
?>
  </coolcode>
 会导致fatal error:
<coolcode lang="shell" linenum="off">
PHP Fatal error:  Class 'b' not found in /home/xinchen/1.php on line 2
Fatal error: Class 'b' not found in /home/xinchen/1.php on line 2
</coolcode>
 分析这个问题，是运行阶段出错，经过分析PHP的编译，执行过程，得出如下的parsing顺序...</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/24/427.html"  title="Permanet Link to PHP5多层继承顺序的bug" >http://www.laruence.com/2008/08/24/427.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>今天guoxiaod提出了一个问题，如下：</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
class a extends b {
};
class b extends c{
};
class c{
};
?&gt;
  </pre>
<p> 会导致fatal error:</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;">
PHP Fatal error:  Class 'b' not found in /home/xinchen/1.php on line 2
Fatal error: Class 'b' not found in /home/xinchen/1.php on line 2
</pre>
<p>分析这个问题，是运行阶段出错，经过分析PHP的编译，执行过程，得出如下的parsing顺序…</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;">
start:
    top_statement_list
;

top_statement_list:
        top_statement_list
.... //有省略
;

top_statement:
.... //有省略
    |   class_declaration_statement
 .... //有省略
;

class_declaration_statement:
        unticked_class_declaration_statement
;

unticked_class_declaration_statement:
        class_entry_type T_STRING extends_from
.... //有省略
;

class_entry_type:
        T_CLASS
.... //有省略
;

extends_from:
        /* empty */
    |   T_EXTENDS fully_qualified_class_name
.... //有省略
;
fully_qualified_class_name:
        T_STRING { zend_do_fetch_class(&amp;$$, &amp;$1 TSRMLS_CC); }
;
</pre>
<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_do_fetch_class 会设置opcode = ZEND_FETCH_CLASS
</pre>
<p>从这个过程我们可以发现，这个应该是PHP5的bug， 对于fully_qualified_class_name，如果fully_qualified_class_name也是继承来自一个类，那么就会出错， 因为fully_qualified_class_name只是简单的去fetch_class, 而如果这个时候，这个类还没有被填入到class_table就会出错。也就是说，需要有个机制，来保证父class首先被处理。</p>
<p>以下是我分析源码后的结论：<br/>
对于a，因为是个派生类，在编译阶段，当遇到它的定义的时候，会：</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_do_begin_class_declaration
</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;">
 build_runtime_defined_function_key(&amp;opline-&gt;op1.u.constant, lcname, name_len TSRMLS_CC);
</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;">
   sprintf(result-&gt;value.str.val, &quot;%c%s%s%s&quot;, '\0', name, filename, char_pos_buf);
</pre>
<p>的字符串，来做为一个编译器的classname存入class_table:</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_hash_update(CG(class_table), opline-&gt;op1.u.constant.value.str.val, opline-&gt;op1.u.constant.value.str.len, &amp;new_class_entry, sizeof(zend_class_entry *), NULL);
</pre>
<p>最后在吸收top_statement的时候，会有一次类的生成(填入class_table);</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;">
top_statement:
        statement
 ...
    |   class_declaration_statement     { zend_do_early_binding(TSRMLS_C); }
...
...
;
</pre>
<p>在zend_do_early_binding的时候：</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;">
void zend_do_early_binding(TSRMLS_D){
...
...
  switch (opline-&gt;opcode) {
      case ZEND_DECLARE_FUNCTION:
          if (do_bind_function(opline, CG(function_table), 1) == FAILURE) {
              return;
          }
          table = CG(function_table);
          break;
      case ZEND_DECLARE_CLASS:
      case ZEND_DECLARE_INHERITED_CLASS:
          is_abstract_class = 1;
          /* break missing intentionally */
      case ZEND_VERIFY_ABSTRACT_CLASS: {
              zend_op *verify_abstract_class_op = opline;

              if (!is_abstract_class) {
                  opline--;
              }
              if (opline-&gt;opcode == ZEND_DECLARE_CLASS) {
                  if (do_bind_class(opline, CG(class_table), 1 TSRMLS_CC) == NULL) {
                      return;
                  }
              } else if (opline-&gt;opcode == ZEND_DECLARE_INHERITED_CLASS) {
                  zval *parent_name = &amp;(opline-1)-&gt;op2.u.constant;
                  zend_class_entry **pce;

                    if (zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &amp;pce TSR
MLS_CC) == FAILURE) {
                        return;
                    }
                    if (do_bind_inherited_class(opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL)
 {
                        return;
                    }
                    /* clear unnecessary ZEND_FETCH_CLASS opcode */
}
</pre>
<p>看到了吧，如果找不到父类，就直接返回了，也就是说，派生类在编译期如果找不到父类，就不会被真正初始化，而是推迟到执行期。会分配一个opcode为ZEND_DECLARE_INHERITED_CLASS的opline，用来在运行期真正生成定义的类：</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 zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC)
{
.......
//hash_merg子类和父类的属性、方法
    if (zend_hash_add(class_table, opline-&gt;op2.u.constant.value.str.val, opline-&gt;op2.u.constant.value.str.len+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE)
.....
}
</pre>
<p>这个时候问题就来了：<br/>
因为我们的b也是一个派生类，所以在执行a的do_bind_inherited_class时候，对于b，他也需要做一个ZEND_DECLARE_INHERITED_CLASS，也就是说，此时的class_table中是没有b的。<br/>
这也就解释了，如果最基类c，定义在前的时候，就不会出错。</p>
<p>恩，这个应该是PHP5的一个Bug。 </p>
<p>我已经报bug给PHP开发组并发信询问Rasmus Lerdof(the creator of PHP)，看他们怎么说了：<br/>
<a href="http://bugs.php.net/bug.php?id=45904" >http://bugs.php.net/bug.php?id=45904</a>
</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_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_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_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_php.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/24/427.html" >2008/08/24</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >guoxiaod</a> writes: 不过，按照这个逻辑的话，似乎就是这么设计的。</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2008/08/24</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >guoxiaod</a> writes: 给 rasmus 发个信 ?</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2008/08/24</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 报了bug了，看看PHP开发组怎么回应吧。</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2008/08/25</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >guoxiaod</a> writes: 这样似乎可以想的通
bind 的时候只有 c 是存在的
执行的时候 自然找不到 b
而 如果c 在前的话 ， b 就bind 了
自然 b就可以找到了</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2008/08/25</a>, <a href="http://www.surfchen.org"  rel="external nofollow"  class="url" >surfchen</a> writes: 这个bug有人报过。http://bugs.php.net/bug.php?id=6418</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2008/08/25</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 哦？看到了，他是针对PHP4， 另外也没关系，起码我们分析出原因了。
也就明白了，为什么单层继承不会出问题。
并且，对于上例，如果c定义在前，也不会出问题。</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2008/08/26</a>, chinawolfs writes: 
执行这样应该不会有什么问题的.顺序的情况</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2008/09/08</a>, x writes: [25 Aug 9:13am UTC] tularis@php.net 
Please do not submit the same bug more than once. An existing
bug report already describes this very problem. Even if you feel
that your issue is somewhat different, the resolution is likely
to be the same. 

Thank you for your interest in PHP.

Duplicate of bug #45903</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2010/09/29</a>, 好消息 writes: 好消息1.纵观社会的发展方向,<a href="http://www.hendrex.com.cn/main/20081289304942/Page/201041221543012/"  rel="nofollow" >火花机</a>行业拥有良好的发展趋势,并且已经成为一个传统而又崭新的创业领域。<a href="http://www.hendrex.com.cn/main/20081289304942/page/2010541721323/"  rel="nofollow" >上海加工中心</a>目前,随着我国经济的快速发展,对<a href="http://www.hendrex.com.cn/main/20081289304942/page/20105170525484/"  rel="nofollow" >苏州火花机</a>机械行业的加大了重视度,尤其是矿山机械。随着近几年,砂石冶金等行业生产规模的扩大,<a href="http://www.hendrex.com.cn"  rel="nofollow" >加工中心维修</a>其对人工机制砂的需求越来越大：2.秋季美容<a href="http://www.shendayumei.cn"  rel="nofollow" >护肤</a>:水嫩不干燥 <a href="http://www.shendayumei.cn"  rel="nofollow" >美容</a>秋季护理大，简要内容:爱美女性往往会过多关心面部的青春娇美,却易忽视自己颈部的保养。<a href="http://www.nj4006.com"  rel="nofollow" >400</a>尤其是在干燥的秋季,颈部皮肤容易老化,粗糙无光、松弛多皱。<a href="http://www.zjhuanbao.com.cn"  rel="nofollow" >浙江环保设备采购</a>每天晚上洗浴时,用含碱少的温和型香皂洗涤颈部,<a href="http://dt.wx35.com"  rel="nofollow" >江苏墙体广告</a>用松软毛巾擦干,再进行按摩。</li><li><a href="http://www.laruence.com/2008/08/24/427.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=152"  rel="external nofollow"  class="url" >PHP5多层继承顺序的bug | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/24/427.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/2010/05/28/1565.html"  rel="bookmark"  title="Permanent Link: PHP错误抑制符(@)导致引用传参失败的Bug" >PHP错误抑制符(@)导致引用传参失败的Bug</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/2011/12/30/2440.html"  rel="bookmark"  title="Permanent Link: PHP5.2.*防止Hash冲突拒绝服务攻击的Patch" >PHP5.2.*防止Hash冲突拒绝服务攻击的Patch</a></li><li><a href="http://www.laruence.com/2010/09/27/1754.html"  rel="bookmark"  title="Permanent Link: PHP stream未能及时清理现场导致Core的bug" >PHP stream未能及时清理现场导致Core的bug</a></li><li><a href="http://www.laruence.com/2008/09/20/523.html"  rel="bookmark"  title="Permanent Link: PHP5.3 α2初体验" >PHP5.3 α2初体验</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/2011/03/22/1929.html"  title="PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2010/05/28/1565.html"  title="PHP错误抑制符(@)导致引用传参失败的Bug" >PHP错误抑制符(@)导致引用传参失败的Bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  title="PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html"  title="PHP5.2.x + APC的一个bug的定位" >PHP5.2.x + APC的一个bug的定位</a></li><li><a href="http://www.laruence.com/2012/02/08/2528.html"  title="PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)" >PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)</a></li><li><a href="http://www.laruence.com/2012/02/02/2515.html"  title="我们什么时候应该使用异常?" >我们什么时候应该使用异常?</a></li><li><a href="http://www.laruence.com/2012/02/01/2503.html"  title="使用exit(-1)为什么得到255退出码?" >使用exit(-1)为什么得到255退出码?</a></li><li><a href="http://www.laruence.com/2012/01/11/2482.html"  title="PHP的历史" >PHP的历史</a></li><li><a href="http://www.laruence.com/2012/01/10/2469.html"  title="如何设置一个严格30分钟过期的Session" >如何设置一个严格30分钟过期的Session</a></li><li><a href="http://www.laruence.com/2012/01/07/2453.html"  title="2012年1月全球www网站技术报告" >2012年1月全球www网站技术报告</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/24/427.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>

