<?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>风雪之隅</title>
	<atom:link href="http://www.laruence.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.laruence.com</link>
	<description>PHP源码分析,Zend引擎分析,Web相关技术研究,Web技术分享--左手代码 右手诗</description>
	<lastBuildDate>Fri, 05 Feb 2010 07:24:03 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Facebook性能大提升的秘密：HipHop</title>
		<link>http://www.laruence.com/2010/02/03/1283.html</link>
		<comments>http://www.laruence.com/2010/02/03/1283.html#comments</comments>
		<pubDate>Wed, 03 Feb 2010 03:00:08 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[转载]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[hiphop]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1283</guid>
		<description><![CDATA[评论: 从最早听说Facebook搞一个神奇的项目开始, 我就在猜测它会怎么做? 想APC一样编译成Opcode? 或者是象phc从Opcode再次加工. 但, 今天看到的介绍, 让我还是有点出乎意料...哪就是- HipHop提供编译器, 让你可以"用PHP的语法写C++代码".

以下为转载原文:Facebook神秘的PHP项目HipHop for  PHP终于揭开面纱。这个项目由一个PHP到C++的转换程序，一个重新实现的PHP运行库，和许多常用PHP扩展的重写版本构成，目的是旨在加速和优化 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/2010/02/03/1283.html"  title="Permanet Link to Facebook性能大提升的秘密：HipHop" >http://www.laruence.com/2010/02/03/1283.html</a></li>
<li>文章转自: <a href="http://www.csdn.net/"  target="_blank" >CSDN</a></li>
</ul></div>
<p>评论: 从最早听说Facebook搞一个神奇的项目开始, 我就在猜测它会怎么做? 想APC一样编译成Opcode? 或者是象phc从Opcode再次加工. 但, 今天看到的介绍, 让我还是有点出乎意料&#8230;哪就是- HipHop提供编译器, 让你可以&#8221;用PHP的语法写C++代码&#8221;.</p>
<p>以下为转载原文:<br/>
<a href="http://www.laruence.com/wp-content/uploads/20100203-044306-pic1.png" ><img class="alignright size-full wp-image-1286"  title="20100203-044306-pic1"  src="http://www.laruence.com/wp-content/uploads/20100203-044306-pic1.png"  alt=""  width="213"  height="278" /></a>Facebook神秘的PHP项目HipHop for  PHP终于揭开面纱。这个项目由一个PHP到C++的转换程序，一个重新实现的PHP运行库，和许多常用PHP扩展的重写版本构成，目的是旨在加速和优化 PHP。</p>
<p>用<a href="http://developers.facebook.com/news.php?story=358blog=1" >Facebook 官方博客</a>（无法直接访问）上项目负责人赵海平（北大1987届遗传与分子生物专业，普林斯顿计算机科学博士）的话说，HipHop项目对 Facebook影响巨大。它目前已经支撑了Facebook 90%的Web流量。由于HipHop，Facebook  Web服务器上的CPU使用平均减少了50%，从而大大减少了服务器的需求。为了让这一改进也惠及社区，他们决定将之开源，希望能够进一步帮助提高更多大 型复杂PHP网站的可伸缩性。</p>
<p><strong>PHP和Facebook的问题</strong></p>
<p>众所周知，Facebook的前端主要是用PHP写的。赵海平说，过去六年Facebook从PHP语言的进展上获益良多。PHP非常简单，易学易 用，好读好调试，因此新工程师成长很快，有利地促进了Facebook的更快的创新。<br/>
<a href="http://www.laruence.com/wp-content/uploads/20100203-043453-pic1.jpg" ><img class="alignright size-full wp-image-1287"  title="20100203-043453-pic1"  src="http://www.laruence.com/wp-content/uploads/20100203-043453-pic1.jpg"  alt=""  width="200"  height="200" /></a></p>
<p>PHP是一种脚本语言，其好处是编程效率高，能够支持产品的快速迭代。但是与传统的编译语言相比，脚本语言的CPU和内存使用效率不好。随着 Ajax技术的广泛采用，加上SNS对动态要求较高，这些缺点更显得突出。对于每月超过4000亿次PV的Facebook来说，如何实现扩展，尤其具有 挑战性。</p>
<p>常见的办法是直接用C++重写PHP应用中比较复杂的部分，作为PHP扩展。实际上，PHP就转变为一种胶水语言，连接前端HTML和C++应用逻 辑。从技术角度讲这也没有问题，但是增加了技能需求，能够在整个应用上工作的工程师数量就大大减少了。学习C++只是编写PHP扩展的第一步，接下来还要 理解Zend  API。由于Facebook的工程团队较小，每个工程师要支持100万以上的用户。有些代码不是团队里每个人都能看懂，这对于Facebook是无法接 受的。</p>
<p>Facebook网站本身的可伸缩性更具挑战性，因为几乎每次页面浏览都是有个性化体验的登录用户发起。浏览主页  时，系统需要查询所有朋友、朋友最重要的状态更新、  根据隐私设置筛选结果，然后还要显示评论、照片等等动态，这一切都需要在一秒内完  成。</p>
<p>自2007年以来，Facebook曾写过几种不同办法解决这些问题。其中包括用另   一种语言重写Facebook，但是由于开发的复杂性和速度等原因，未能实现。他们还重写了PHP的核心部分Zend引擎，并提交给了PHP项目，但最终 还是没有获得所需的性能。最后，他们选择了HipHop，终于得偿所愿。</p>
<p>有了HipHop，工程师可以编写代码，用PHP编写组合最后页面的逻辑，并能够继续快速迭代，同时后端服务使用C++, Erlang,  Java, Py  thon编写，提供新闻提要、搜索、聊天和其他核心功能。</p>
<p><strong>HipHop开发故事</strong></p>
<p>赵海平透露，项目最初是来自几年前Facebook公司一次Hackathon活动（员工在一个晚上自由发挥，实验新的想法），他手工将PHP转换 为C++代码，虽然语法上很类似，但是无论是CPU还是内存使用，转换后的C++代码都大大优于PHP。于是他想，如果构建一个系统，编程实现转换，会怎 么样呢？</p>
<p>在此之前，已经有了不少改善PHP性能的方法。Zend引擎在运行时转换PHP源代码为运行在Zend虚拟机上的opcode。开源项目APC和 eAccelerator将输出缓存，为大多数PHP网站所使用。此外，还有Zend  Server这样的商业产品，通过opcode优化和缓存，提高PHP速度。赵海平选择了另一条道路，将PHP直接转为C++，然后再变成本地机器码。当 然，有许多开源项目也是同样的思路，Roadsend和phc编译为C，Quercus编译为Java，而Phalanger编译为.NET。</p>
<p>Hackathon之后8个月，赵海平拿出了原型，足以说明这条路可以走通，编译后的代码的确更快。不久，Iain  Proctor和Minghui  Yang加入进来。接下来又开发了10个月，在生产服务器上测试了6个月。然后正式上线部署，6个月之后，Facebook  90%以上的Web流量都使用了HipHop。</p>
<p>按赵海平的说法，凭借HipHop，Facebook  Web服务器上的CPU使用平均减少了50%，从而大大减少了服务器的需求。项目对Facebook影响巨大。为了让这一改进也惠及社区，他们决定将之开 源，希望能够进一步帮助提高更多大型复杂PHP网站的可伸缩性。</p>
<div id="attachment_1288"  class="wp-caption aligncenter"  style="width: 660px" ><a href="http://www.laruence.com/wp-content/uploads/20100203-050719-pic1.jpg" ><img class="size-full wp-image-1288"  title="20100203-050719-pic1"  src="http://www.laruence.com/wp-content/uploads/20100203-050719-pic1.jpg"  alt=""  width="650"  height="406" /></a><p class="wp-caption-text" >Hiphop for PHP transformation process</p></div>
<p><strong>HipHop的原理</strong></p>
<p>HipHop将PHP代码转换为高度优化的C++代码，然后再用g++编译器编译。它可以保持语义等效地执行源代码，但为了提高性能，牺牲了一些很 少用到的特性，比如eval()。</p>
<p>HipHop开发中的主要困难在于，在PHP和C++这两种很不一样的语言之间怎么实现转换。虽然PHP也可以写一些很巧妙的动态特性，但是大多数 PHP代码还是非常简单的。if (&#8230;) {&#8230;} else {..} 比foo($x) { include $x; }  肯定更常见。这为性能提高提供了机会。HipHop生成的代码尽可能地使用函数和变量的静态绑定。同时，还使用类型推演来选出变量最可能对应的某个类型， 从而节省内存。</p>
<p>转换过程分三步：</p>
<p>1. 静态分析。收集声明关系和依赖关系等信息。</p>
<p>2. 类型推演。选择最合适的类型，是C++的标量？还是String, Array, classes, Object或者Variant。</p>
<p>3. 代码生成。大部分直接将PHP语句和表达式对应为C++的语句和表达式。</p>
<p>在开发过程中，还有一个副产品：HPHPi，是一个实验性的解释器。通过它，不编译PHP源代码也可以运行。它已经用于HipHop自身的调试中。</p>
<p>HipHop在保持了PHP优点的同时，也兼得了C++的性能优势。项目总共有30万行代码，5000多个单元测试。所有这些都将以PHP开源许可 证形式发布到GitHub。</p>
<p>更多信息，可以申请加入HipHop的邮件列表：</p>
<p><a href="http://groups.google.com/group/hiphop-php-dev" >http://groups.google.com/group/hiphop-php-dev</a></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/02/03/1283.html#comment-2458" >2010/02/04</a>, <a href="http://www.909520.cn"  rel="external nofollow"  class="url" >侯良</a> writes: 这个是个好东西。
一定要把它学会 。</li><li><a href="http://www.laruence.com/2010/02/03/1283.html#comment-2459" >2010/02/05</a>, <a href="http://www.nnbizhi.com"  rel="external nofollow"  class="url" >cnan</a> writes: 感觉想不想google的用java写JavaScript</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/02/03/1283.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>注意PHP5.2.11之后的json_decode</title>
		<link>http://www.laruence.com/2010/02/02/1272.html</link>
		<comments>http://www.laruence.com/2010/02/02/1272.html#comments</comments>
		<pubDate>Tue, 02 Feb 2010 10:32:58 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[5.2.11]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[json_decode]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1272</guid>
		<description><![CDATA[<p>
    在PHP5.2.6以前, json_decode一个字符串, 将会返回字符串本身.
<coolcode lang="php" linenum="off">
php -r "var_dump(json_decode('laruence'));"
//输出
string(8)"laruence";
</coolcode>
   但是, 不知道是不是因为之前在php bug中, 有人提议对于这种情况, 因为字符串不是合法的json格式的串, 所以应该出错, 返回NULL(<a href="http://bugs.php.net/bug.php?id=45989" target="_blank">http://bugs.php.net/bug.php?id=45989</a>). 所以在PHP5.2.11之后(具体是从哪个版本开始, 我回头再验证), 竟然返回NULL了.
<coolcode lang="php" linenum="off">
php -r "var_dump(json_decode('laruence'));"
//输出
NULL
</coolcode>
</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2010/02/02/1272.html"  title="Permanet Link to 注意PHP5.2.11之后的json_decode" >http://www.laruence.com/2010/02/02/1272.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
    在PHP5.2.6以前, json_decode一个字符串, 将会返回字符串本身.</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 -r &quot;var_dump(json_decode('laruence'));&quot;
//输出
string(8)&quot;laruence&quot;;
</pre>
<p>   但是, 不知道是不是因为之前在php bug中, 有人提议对于这种情况, 因为字符串不是合法的json格式的串, 所以应该出错, 返回NULL(<a href="http://bugs.php.net/bug.php?id=45989"  target="_blank" >http://bugs.php.net/bug.php?id=45989</a>). 所以在PHP5.2.11之后(具体是从哪个版本开始, 我回头再验证), 竟然返回NULL了.</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 -r &quot;var_dump(json_decode('laruence'));&quot;
//输出
NULL
</pre>
<p>    但值得注意的是, 对于numeric_string, 都是返回numeric_string的数值形式.</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 -r &quot;var_dump(json_decode('0x3f34'));&quot;
//输出
int(16180)
</pre>
<p>    另外, 在PHP5.3以后,可以通过json_last_error()来验证转换是否正确.
</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></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/02/02/1272.html#comment-2452" >2010/02/02</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 因为之前把几个PHP版本的安装路径搞混了, 看错了5.3的实现, 误以为5.3中和5.2.6一致, 抱歉给大家造成误解.</li><li><a href="http://www.laruence.com/2010/02/02/1272.html#comment-2453" >2010/02/02</a>, <a href="http://www.9enjoy.com"  rel="external nofollow"  class="url" >enjoy</a> writes: 我在5.2.8下试了下。
php -r "var_dump(json_decode('laruence'));"
//输出
string(8) "laruence"</li><li><a href="http://www.laruence.com/2010/02/02/1272.html#comment-2454" >2010/02/02</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @enjoy 我看到在5.2.9的release notes中有关于json_decode的, 但不是和这个相关的.</li><li><a href="http://www.laruence.com/2010/02/02/1272.html#comment-2455" >2010/02/02</a>, <a href="http://www.deepseath.com/"  rel="external nofollow"  class="url" >Deepseath</a> writes: 类似这样频繁改动的函数，我会重新写个函数。呵呵，虽然麻烦但兼容性相对好一些，而且一旦确定环境了，进行优化也相对容易一些^_^</li><li><a href="http://www.laruence.com/2010/02/02/1272.html#comment-2456" >2010/02/02</a>, <a href="http://sanmuding.com"  rel="external nofollow"  class="url" >Anders</a> writes: guoxiaod@guoxiaod&gt;php -r 'var_dump(json_decode("\"abc\""));'
string(3) "abc"
guoxiaod@guoxiaod&gt;php -v 
PHP 5.2.10-2ubuntu6.4 with Suhosin-Patch 0.9.7 (cli) (built: Jan  6 2010 22:41:56)</li><li><a href="http://www.laruence.com/2010/02/02/1272.html#comment-2457" >2010/02/02</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @anderson  不要"\"abc\"", 这里是指"abc", ;)</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/02/02/1272.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>pkg-config与LD_LIBRARY_PATH</title>
		<link>http://www.laruence.com/2010/01/27/1265.html</link>
		<comments>http://www.laruence.com/2010/01/27/1265.html#comments</comments>
		<pubDate>Wed, 27 Jan 2010 11:34:28 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[GNU C/C++]]></category>
		<category><![CDATA[转载]]></category>
		<category><![CDATA[随笔]]></category>
		<category><![CDATA[ld.so.conf]]></category>
		<category><![CDATA[LD_LIBRARY_PATH]]></category>
		<category><![CDATA[pkg-config]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1265</guid>
		<description><![CDATA[    一般来说，如果库的头文件不在 /usr/include 目录中，那么在编译的时候需要用 -I 参数指定其路径。由于同一个库在不同系统上可能位于不同的目录下，用户安装库的时候也可以将库安装在不同的目录下，所以即使使用同一个库，由于库的路径的不同，造成了用 -I 参数指定的头文件的路径也可能不同，其结果就是造成了编译命令界面的不统一。如果使用 -L 参数，也会造成连接界面的不统一。编译和连接界面不统一会为库的使用带来麻烦。

       为了解决编译和连接界面不统一的问题，人们找到了一些解决办法。其基本思想就是：事先把库的位置信息等保存起来，需要的时候再通过特定的工具将其中有用的 信息提取出来供编译和连接使用。这样，就可以做到编译和连接界面的一致性。其中，目前最为常用的库信息提取工具就是下面介绍的 pkg-config...]]></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/2010/01/27/1265.html"  title="Permanet Link to pkg-config与LD_LIBRARY_PATH" >http://www.laruence.com/2010/01/27/1265.html</a></li>
<li>文章转自: <a href="http://hi.baidu.com/litaosmile/blog/item/751be4f45bbb4ee67609d7be.html"  target="_blank" >Lucky_xi的百度空间</a></li>
</ul></div>
<p>最近遇到的几个问题， 都和LD_LIBRARY_PATH有关， 想整理一篇心得， 但发现一片比较好的介绍文章， 就不再赘笔了。</p>
<h3>一、编译和连接</h3>
<p>        一般来说，如果库的头文件不在 /usr/include 目录中，那么在编译的时候需要用 -I 参数指定其路径。由于同一个库在不同系统上可能位于不同的目录下，用户安装库的时候也可以将库安装在不同的目录下，所以即使使用同一个库，由于库的路径的不同，造成了用 -I 参数指定的头文件的路径也可能不同，其结果就是造成了编译命令界面的不统一。如果使用 -L 参数，也会造成连接界面的不统一。编译和连接界面不统一会为库的使用带来麻烦。</p>
<p>       为了解决编译和连接界面不统一的问题，人们找到了一些解决办法。其基本思想就是：事先把库的位置信息等保存起来，需要的时候再通过特定的工具将其中有用的 信息提取出来供编译和连接使用。这样，就可以做到编译和连接界面的一致性。其中，目前最为常用的库信息提取工具就是下面介绍的 pkg-config。</p>
<p>       pkg-config 是通过库提供的一个 .pc 文件获得库的各种必要信息的，包括版本信息、编译和连接需要的参数等。这些信息可以通过 pkg-config 提供的参数单独提取出来直接供编译器和连接器使用。</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;">
  The pkgconfig package contains tools for passing the include path and/or library
paths to build tools during the make file execution.

  pkg-config is a function that returns meta information for the specified library.

  The default setting for PKG_CONFIG_PATH is /usr/lib/pkgconfig because of the prefix
we use to install pkgconfig. You may add to PKG_CONFIG_PATH by exporting additional
paths on your system where pkgconfig files are installed. Note that PKG_CONFIG_PATH is
only needed when compiling packages, not during run-time.
</pre>
<p>        在默认情况下，每个支持 pkg-config 的库对应的 .pc 文件在安装后都位于安装目录中的 lib/pkgconfig 目录下。例如，我们在上面已经将 Glib 安装在 /opt/gtk 目录下了，那么这个 Glib 库对应的 .pc 文件是 /opt/gtk/lib/pkgconfig 目录下一个叫 glib-2.0.pc 的文件：</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;">
prefix=/opt/gtk/
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums

Name: GLib
Description: C Utility Library
Version: 2.12.13
Libs: -L${libdir} -lglib-2.0
Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib-2.0/include
</pre>
<p>使用 pkg-config 的 &#8211;cflags 参数可以给出在编译时所需要的选项，而 &#8211;libs 参数可以给出连接时的选项。例如，假设一个 sample.c 的程序用到了 Glib 库，就可以这样编译：</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;">
$ gcc -c `pkg-config --cflags glib-2.0` sample.c
</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;">
$ gcc sample.o -o sample `pkg-config --libs glib-2.0`
</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;">
$ gcc sample.c -o sample `pkg-config --cflags --libs glib-2.0`
</pre>
<p>可以看到：由于使用了 pkg-config 工具来获得库的选项，所以不论库安装在什么目录下，都可以使用相同的编译和连接命令，带来了编译和连接界面的统一。</p>
<p>使用 pkg-config 工具提取库的编译和连接参数有两个基本的前提：</p>
<p>库本身在安装的时候必须提供一个相应的 .pc 文件。不这样做的库说明不支持 pkg-config 工具的使用。</p>
<p>pkg-config 必须知道要到哪里去寻找此 .pc 文件。</p>
<p>GTK+ 及其依赖库支持使用 pkg-config 工具，所以剩下的问题就是如何告诉 pkg-config 到哪里去寻找库对应的 .pc 文件，这也是通过设置搜索路径来解决的。</p>
<p>       对于支持 pkg-config 工具的 GTK+ 及其依赖库来说，库的头文件的搜索路径的设置变成了对 .pc 文件搜索路径的设置。.pc 文件的搜索路径是通过环境变量 PKG_CONFIG_PATH 来设置的，pkg-config 将按照设置路径的先后顺序进行搜索，直到找到指定的 .pc 文件为止。</p>
<p>安装完 Glib 后，在 bash 中应该进行如下设置：</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;">
$ export PKG_CONFIG_PATH=/opt/gtk/lib/pkgconfig:$PKG_CONFIG_PATH
</pre>
<p>可以执行下面的命令检查是否 /opt/gtk/lib/pkgconfig 路径已经设置在 PKG_CONFIG_PATH 环境变量中：</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;">
$ echo $PKG_CONFIG_PATH
</pre>
<p>这样设置之后，使用 Glib 库的其它程序或库在编译的时候 pkg-config 就知道首先要到 /opt/gtk/lib/pkgconfig 这个目录中去寻找 glib-2.0.pc 了（GTK+ 和其它的依赖库的 .pc 文件也将拷贝到这里，也会首先到这里搜索它们对应的 .pc 文件）。之后，通过 pkg-config 就可以把其中库的编译和连接参数提取出来供程序在编译和连接时使用。</p>
<p>另外还需要注意的是：环境变量的设置只对当前的终端窗口有效。如果到了没有进行上述设置的终端窗口中，pkg-config 将找不到新安装的 glib-2.0.pc 文件、从而可能使后面进行的安装（如 Glib 之后的 Atk 的安装）无法进行。</p>
<p>       在我们采用的安装方案中，由于是使用环境变量对 GTK+ 及其依赖库进行的设置，所以当系统重新启动、或者新开一个终端窗口之后，如果想使用新安装的 GTK+ 库，需要如上面那样重新设置 PKG_CONFIG_PATH 和 LD_LIBRARY_PATH 环境变量。</p>
<p>这种使用 GTK+ 的方法，在使用之前多了一个对库进行设置的过程。虽然显得稍微繁琐了一些，但却是一种最安全的使用 GTK+ 库的方式，不会对系统上已经存在的使用了 GTK+ 库的程序（比如 GNOME 桌面）带来任何冲击。</p>
<p>为了使库的设置变得简单一些，可以把下面的这两句设置保存到一个文件中（比如 set_gtk-2.10 文件）:</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;">
export PKG_CONFIG_PATH=/opt/gtk/lib/pkgconfig:$PKG_CONFIG_PATH
export LD_LIBRARY_PATH=/opt/gtk/lib:$LD_LIBRARY_PATH
</pre>
<p>之后，就可以用下面的方法进行库的设置了（其中的 source 命令也可以用 . 代替）：</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;">
$ source set_gtk-2.10
</pre>
<p>只有在用新版的 GTK+ 库开发应用程序、或者运行使用了新版 GTK+ 库的程序的时候，才有必要进行上述设置。</p>
<p>           如果想避免使用 GTK+ 库之前上述设置的麻烦，可以把上面两个环境变量的设置在系统的配置文件中（如 /etc/profile）或者自己的用户配置文件中（如 ~/.bash_profile） ；库的搜索路径也可以设置在 /etc/ld.so.conf 文件中，等等。这种设置在系统启动时会生效，从而会导致使用 GTK+ 的程序使用新版的 GTK+ 运行库，这有可能会带来一些问题。当然，如果你发现用新版的 GTK+ 代替旧版没有什么问题的话，使用这种设置方式是比较方便的。加入到~/.bashrc中，例如：</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;">
PKG_CONFIG_PATH=/opt/gtk/lib/pkgconfig
</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;">
[root@localhost ~]# echo $PKG_CONFIG_PATH
/opt/gtk/lib/pkgconfig
</pre>
<h3> 二、运行时 </h3>
<p>        库文件在连接（静态库和共享库）和运行（仅限于使用共享库的程序）时被使用，其搜索路径是在系统中进行设置的。一般 Linux 系统把 /lib 和 /usr/lib 两个目录作为默认的库搜索路径，所以使用这两个目录中的库时不需要进行设置搜索路径即可直接使用。对于处于默认库搜索路径之外的库，需要将库的位置添加到 库的搜索路径之中。设置库文件的搜索路径有下列两种方式，可任选其一使用：</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;">
在环境变量 LD_LIBRARY_PATH 中指明库的搜索路径。
在 /etc/ld.so.conf 文件中添加库的搜索路径。
</pre>
<p>        将自己可能存放库文件的路径都加入到/etc/ld.so.conf中是明智的选择 ^_^<br/>
添加方法也极其简单，将库文件的绝对路径直接写进去就OK了，一行一个。例如：</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;">
/usr/X11R6/lib
/usr/local/lib
/opt/lib
</pre>
<p>        需要注意的是：第二种搜索路径的设置方式对于程序连接时的库（包括共享库和静态库）的定位已经足够了，但是对于使用了共享库的程序的执行还是不够的。这是 因为为了加快程序执行时对共享库的定位速度，避免使用搜索路径查找共享库的低效率，所以是直接读取库列表文件 /etc/ld.so.cache 从中进行搜索的。/etc/ld.so.cache 是一个非文本的数据文件，不能直接编辑，它是根据 /etc/ld.so.conf 中设置的搜索路径由 /sbin/ldconfig 命令将这些搜索路径下的共享库文件集中在一起而生成的（ldconfig 命令要以 root 权限执行）。因此，为了保证程序执行时对库的定位，在 /etc/ld.so.conf 中进行了库搜索路径的设置之后，还必须要运行 /sbin/ldconfig 命令更新 /etc/ld.so.cache 文件之后才可以。ldconfig ,简单的说，它的作用就是将/etc/ld.so.conf列出的路径下的库文件 缓存到/etc/ld.so.cache 以供使用。因此当安装完一些库文件，(例如刚安装好glib)，或者修改ld.so.conf增加新的库路径后，需要运行一下 /sbin/ldco                                 .cache中，如果没做，即使库文件明明就在/usr/lib下的，也是不会被使用 的，结果编译                                现明明就在那放着，搞的想大骂computer蠢猪一个。 ^_^</p>
<p>       在程序连接时，对于库文件（静态库和共享库）的搜索路径，除了上面的设置方式                                 。因为用 -L 设置的路径将被优先搜索，所以在连接的时候通常都会以这种方式直接指定</p>
<p>        前面已经说明过了，库搜索路径的设置有两种方式：在环境变量 LD_LIBRARY_PA                                文件中设置。其中，第二种设置方式需要 root 权限，以改变 /etc/ld.so.conf 文件并执                                 系统重新启动后，所有的基于 GTK2 的程序在运行时都将使用新安装的 GTK+ 库。不幸的                                会给应用程序带来兼容性的问题，造成某些程序运行不正常。为了避免出现上面的这些情                                中对于库的搜索路径的设置将采用第一种方式进行。这种设置方式不需要 root 权限，设</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;">
$ export LD_LIBRARY_PATH=/opt/gtk/lib:$LD_LIBRARY_PATH
</pre>
<p>可以用下面的命令查看 LD_LIBRAY_PATH 的设置内容：</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;">
$ echo $LD_LIBRARY_PATH
</pre>
<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_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><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><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><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/><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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/01/27/1265.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IE下var的重要性的又一佐证</title>
		<link>http://www.laruence.com/2010/01/21/1254.html</link>
		<comments>http://www.laruence.com/2010/01/21/1254.html#comments</comments>
		<pubDate>Thu, 21 Jan 2010 04:43:07 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[Js/CSS]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[var]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1254</guid>
		<description><![CDATA[ 一个朋友问了一个js问题, 一段看不出有任何问题的代码, 在ie下报错:"object doesn't support this property or method".
 <coolcode lang="javascript" linenum="off">
function foo(obj) {
   productTree = obj.toString();
   document.getElementById('productTree').innerHTML = productTree;
} 
</coolcode>
</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2010/01/21/1254.html"  title="Permanet Link to IE下var的重要性的又一佐证" >http://www.laruence.com/2010/01/21/1254.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   一个朋友问了一个js问题, 一段看不出有任何问题的代码, 在ie下报错:&#8221;object doesn&#8217;t support this property or method&#8221;.</p>
<pre name="code"  class="sh_javascript"  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;">
function foo(obj) {
   productTree = obj.toString();
   document.getElementById('productTree').innerHTML = productTree;
}
</pre>
<p>    开始, 还以为错误是指obj的toString方法, 绕了半天弯路, 无果..</p>
<p>    后来,注意到变量名是productTree没有用var申明, 加上getElementById(&#8216;productTree&#8217;)说明有个id为productTree的元素, 并且我们知道在IE下可以直接通过id获取DOM元素的引用, so~</p>
<p>    所以啊, 局部变量一定要用var申明, 不仅仅是因为不用var会成全局变量, 更因为在IE下, 有可能会出现这种, 让人很莫名的错误&#8230;.
</p>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_javascript.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/01/21/1254.html#comment-2440" >2010/01/21</a>, rzhome writes: 在IE下就是这样的痛苦，不过加var来声明变量应该规范点。</li><li><a href="http://www.laruence.com/2010/01/21/1254.html#comment-2441" >2010/01/21</a>, yangliang writes: 难道window下的所有变量ie都认为是dom咯，该死的ie</li><li><a href="http://www.laruence.com/2010/01/21/1254.html#comment-2442" >2010/01/22</a>, janpoem writes: 这是ie的老问题了，应该规范使用var声明变量。</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/01/21/1254.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Nginx/PHP Fastcgi PATH_INFO的一个问题</title>
		<link>http://www.laruence.com/2010/01/20/1247.html</link>
		<comments>http://www.laruence.com/2010/01/20/1247.html#comments</comments>
		<pubDate>Tue, 19 Jan 2010 16:24:40 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[path_info]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[urldecode]]></category>
		<category><![CDATA[urlencode]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1247</guid>
		<description><![CDATA[通过<a href="http://www.laruence.com/2009/11/13/1138.html" target="_blank">在nginx.conf中模拟PATH_INFO</a>的方法会有一个bug. 那就是PATH_INFO不会被urldecode.
 
    对于Apache+PHP(php2handler)来说, PATH_INFO来自Apache, 不会有问题, 对于Apache fastcgi也应该没有问题, 因为PATH_INFO也是由Apache生成.

    但是对于nginx+fastcgi, 因为对于cgi来说PATH_INFO来自于ENV(fastcgi_params), 而php-cgi中的import_environment_variables不会对ENV中的变量做urldecode. 

    这样, nginx看到的url是urlencode以后的, 从url中分离出来的PATH_INFO也是urlencode后的, forward给php proxy以后, PHP看到的PATH_INFO也是urlencode的了. 

    所以, 如果在PATH_INFO中包含一些宽字符, 或者是"+", 那就要注意了, 需要我们主动的urldecode一下再使用.]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2010/01/20/1247.html"  title="Permanet Link to Nginx/PHP Fastcgi PATH_INFO的一个问题" >http://www.laruence.com/2010/01/20/1247.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>    通过<a href="http://www.laruence.com/2009/11/13/1138.html"  target="_blank" >在nginx.conf中模拟PATH_INFO</a>的方法会有一个bug. 那就是PATH_INFO不会被urldecode.</p>
<p>    对于Apache+PHP(php2handler)来说, PATH_INFO来自Apache, 不会有问题, 对于Apache fastcgi也应该没有问题, 因为PATH_INFO也是由Apache生成.</p>
<p>    但是对于nginx+fastcgi, 因为对于cgi来说PATH_INFO来自于ENV(fastcgi_params), 而php-cgi中的import_environment_variables不会对ENV中的变量做urldecode. </p>
<p>    这样, nginx看到的url是urlencode以后的, 从url中分离出来的PATH_INFO也是urlencode后的, forward给php proxy以后, PHP看到的PATH_INFO也是urlencode的了. </p>
<p>    所以, 如果在PATH_INFO中包含一些宽字符, 或者是&#8221;+&#8221;, 那就要注意了, 需要我们主动的urldecode一下再使用.</p>
<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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/01/20/1247.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Youtube解封啦!</title>
		<link>http://www.laruence.com/2010/01/03/1233.html</link>
		<comments>http://www.laruence.com/2010/01/03/1233.html#comments</comments>
		<pubDate>Sun, 03 Jan 2010 15:16:51 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[随笔]]></category>
		<category><![CDATA[youtube]]></category>
		<category><![CDATA[解封]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1233</guid>
		<description><![CDATA[<p>
事实证明,是gfw升级间隙造成的短暂开放.
</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2010/01/03/1233.html"  title="Permanet Link to Youtube解封啦!" >http://www.laruence.com/2010/01/03/1233.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
事实证明,是gfw升级间隙造成的短暂开放. 只有5个小时&#8230;</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/01/03/1233.html#comment-2410" >2010/01/03</a>, <a href="http://www.royalar.cn"  rel="external nofollow"  class="url" >royalar</a> writes: 部分地区因为g...f..w--list调整而解封的，我这里就打不开</li><li><a href="http://www.laruence.com/2010/01/03/1233.html#comment-2411" >2010/01/04</a>, kwjlk writes: 果然是啊，访问不来</li><li><a href="http://www.laruence.com/2010/01/03/1233.html#comment-2412" >2010/01/04</a>, zong writes: 是啊 ，我这果然不能访问</li><li><a href="http://www.laruence.com/2010/01/03/1233.html#comment-2414" >2010/01/04</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: sign, 见证了youtube的短暂回光返照.... 看来确实是g-f-w的技术问题.</li><li><a href="http://www.laruence.com/2010/01/03/1233.html#comment-2415" >2010/01/04</a>, venkman writes: 一把火把g，w，f烧了</li><li><a href="http://www.laruence.com/2010/01/03/1233.html#comment-2417" >2010/01/04</a>, <a href="http://liuqingyan.blogspot.com"  rel="external nofollow"  class="url" >qy</a> writes: 我说昨天咋忽然能看wordpress了呢。。。。汗</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/01/03/1233.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>一个想当然造成的错误(赋值语句的返回值)</title>
		<link>http://www.laruence.com/2010/01/03/1225.html</link>
		<comments>http://www.laruence.com/2010/01/03/1225.html#comments</comments>
		<pubDate>Sun, 03 Jan 2010 09:53:27 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[函数调用]]></category>
		<category><![CDATA[引用]]></category>
		<category><![CDATA[引用参数]]></category>
		<category><![CDATA[赋值]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1225</guid>
		<description><![CDATA[	一个想当然造成的错误.

	需求是这样的, 我需要给一个二进制流加入一个签名串. 那么首先, 理所当然我的写了一个签名函数, 考虑到要判断签名操作是否成功, 所以我采用了传引用:

<coolcode lang="php" linenum="off">
function sign(&#038;$carrier, $fingerprint) {
	if (NULL === $fingerprint) {
		return FALSE;
	}
	//加入签名
	$carrier = 签名逻辑.
	return TRUE;
}
</coolcode> 

	接下来, 考虑到, 如果签名失败, 那还是使用原来的字符串做为结果, 所以, 我想当然的写下了如下的代码....]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2010/01/03/1225.html"  title="Permanet Link to 一个想当然造成的错误(赋值语句的返回值)" >http://www.laruence.com/2010/01/03/1225.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	一个想当然造成的错误.</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;">
function sign(&amp;$carrier, $fingerprint) {
	if (NULL === $fingerprint) {
		return FALSE;
	}
	//加入签名
	$carrier = 签名逻辑.
	return TRUE;
}
</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;">
$bin_str = **************;

$success = sign($after_signed = $bin_str, &quot;laruence's fingerprint&quot;);
if ($success) {
	//使用$after_signed
} else {
	//使用$bin_str
}
</pre>
<p>考虑到简单变量是传值引用, 在bin_str赋值给after_signed以后, 我以为after_signed的引用会传递给carrier..<br/>
但, 结果是, after_signed并没有被加入签名串&#8230;</p>
<p>那为什么会错呢?</p>
<p>经过对opcode的分析, 发现原来, 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;">
$a = $b;
</pre>
<p>它的返回值, 并不是$a, 而是一个临时变量, 假设是$2.<br/>
所以传递给sign函数的, 并不是$a的引用, 而是$2;</p>
<p>以下内容是对源码的分析范畴, 如果只是想知道结论的, 略过如下也可:</p>
<p>现在, 结合之前的文章<a href="http://www.laruence.com/2008/09/19/520.html" >深入理解PHP原理之变量分离/引用(Variables Separation)</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;">
$a = &quot;laruence&quot;;
function ch(&amp;$p) {
    debug_zval_dump($p);
    $p = 'eve';
    debug_zval_dump($p);
}

debug_zval_dump($a);
ch($a);
ch($b=$a);
</pre>
<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;">
//初始的a
string(8) &quot;laruence&quot; refcount(2)
//第一次调用change中的p
string(8) &quot;laruence&quot; refcount(1)
string(3) &quot;eve&quot; refcount(1)
//第二次赋值结果调用change中的a
string(3) &quot;eve&quot; refcount(3)
string(3) &quot;eve&quot; refcount(2)
</pre>
<p>首先, 最初的时候, $a的引用是2, 这是因为简单变量传值, 所以传给debug_zval_dump后, $a有一个copy的引用计数. </p>
<p>当第一次调用的时候, 我们直接传$a, 因为change函数的参数申明是传引用, 在change中调用debug_zval_dump时, $p是一个引用. 而要传值调用, 所以产生了一次分离, 得到计数为1.</p>
<p>重点看下第二次调用, 此时change中第一次debug_zval_dump的引用计数是3. 怎么会是3呢?.<br/>
此处要是3. 那也就是说$p是一个引用计数为2的非引用变量.</p>
<p>可是, 明明不是申明了change接受引用参数么?</p>
<p>没办法, 查看源代码. 在语法分析时刻, 看出了差别:</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;">
non_empty_function_call_parameter_list:
        expr_without_variable
		   { Z_LVAL($$.u.constant) = 1;
				zend_do_pass_param(&amp;$1, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); }
    |   variable
			{ Z_LVAL($$.u.constant) = 1;
				zend_do_pass_param(&amp;$1, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); }
</pre>
<p>对于第二次调用, 它将满足的是第一条规约规则, 也就是传给zend_do_pass_param的第二个参数是ZEND_SEND_VAL&#8230;</p>
<p>继续追查zend_do_pass_param:</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;">
if (op == ZEND_SEND_VAR &amp;&amp; zend_is_function_or_method_call(param)) {
	//是否是函数或者方法的返回值
	/* Method call */
	op = ZEND_SEND_VAR_NO_REF;
	send_function = ZEND_ARG_SEND_FUNCTION;
} else if (op == ZEND_SEND_VAL &amp;&amp; (param-&gt;op_type &amp; (IS_VAR|IS_CV))) {
	op = ZEND_SEND_VAR_NO_REF;//在这里被改成了NO_REF
}
</pre>
<p>也就是, 因为第二次调用的时候传递给change的变量, 是一个&#8221;直接量&#8221;, 并且属于IS_VAR, 所以PHP会把传递方式改变为传值.</p>
<p>所以在change中第一次debug_zval_dump的时候, 引用计数就是3了. ~ </p>
<p>其实, 分析到这里的时候, 我们可以类比函数的返回值做为参数的情形(第一个if判断条件). 想象赋值也和函数调用一样, 有返回值, 就容易理解多了.
</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_sh.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_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/01/03/1225.html#comment-2406" >2010/01/03</a>, LANYE writes: ..嘿嘿</li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2407" >2010/01/03</a>, <a href="http://sanmuding.com"  rel="external nofollow"  class="url" >Anders</a> writes: 有些 trick 样的语句还是少用的好，呵呵。</li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2408" >2010/01/03</a>, PeterYu writes: 5.3开始,直接禁止了引用一个"非明示的变量值".
:-),你可以试试,</li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2409" >2010/01/03</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @PeterYu 在PHP 5.3.0 (cli)下, 关于这个问题的语法分析逻辑以及complie.c中的zend_do_pass_param逻辑和PHP5.2.x一样,经过我测试, 结论和本文的一致.  另外我没听过"非明示变量值"这个名词, 是指匿名变量(变量直接量)么? </li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2421" >2010/01/05</a>, <a href="http://blog.csdn.net/yycai"  rel="external nofollow"  class="url" >小蔡</a> writes: $a = 'test';
$b = &amp; $a; 

function ch(&amp;$p) {
    debug_zval_dump($p);
    $p = 'eve';
    debug_zval_dump($p);
}

debug_zval_dump($a);
ch($a);
ch($b=$a);

为什么这里输出的refcount全都是1呢？</li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2422" >2010/01/05</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @小蔡 b是a的引用, 调用的时候要传值, 所以就产生分离了啊.</li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2423" >2010/01/05</a>, <a href="http://blog.csdn.net/yycai"  rel="external nofollow"  class="url" >小蔡</a> writes: 感觉还是有点乱，晚上回去看看源码</li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2426" >2010/01/07</a>, <a href="http://www.zhouxblog.com"  rel="external nofollow"  class="url" >shinezhou</a> writes: $a = $b这个表达式的结果竟然不是左值$a...
让人郁闷了~</li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2433" >2010/01/16</a>, <a href="http://www.editornote.net"  rel="external nofollow"  class="url" >erway</a> writes: 博主：你好！
我是机械工业出版社华章公司（www.hzbook.com，中国IT出版4强）的高级策划编辑杨福川，冒昧打扰了，还请见谅。
今天无意中从一位朋友的博客中链接到了你的博客中，顿时眼前一亮，原来又发现了一位高人。我一直想策划一本关于PHP源码剖析的书，苦于找不到作者，没想到今天无意中发现了一位大牛，庆幸哉！我仔细拜读了你撰写的关于PHP的文章，看得出来你对PHP颇有研究，似乎对PHP源码情有独钟，何不系统性地来分析一下PHP的源码呢？这不但能造福广大PHPer，也许能成为你人生的一个转折点，哈哈。
我准备策划一系列关于源码分析的书，目前已经出版和策划的有：
1. 《Spring技术内幕——深入解析Spring架构与设计原理》，最近刚出版，当当网2天就卖断货。
2. 《Struts技术内幕——深入解析Struts架构与设计原理》，正在策划中。
3. 《JVM技术内幕》，正在策划中。
4. 《MySQL技术内幕》，正在策划中。

《PHP技术内幕》也是我策划的这套书中非常重要的一本，一直还没有找到比较合适的朋友来写，今日认识了兄弟你，我想也许我找到了这个选题的主人，不知道是否有机会与你合作。为了便于联系，能否交换一下联系方式（MSN：erwa_yang@live.cn；QQ：15693352）？

期待与你取得联系，期待与你合作。</li><li><a href="http://www.laruence.com/2010/01/03/1225.html#comment-2439" >2010/01/20</a>, <a href="http://dev.meettea.com"  rel="external nofollow"  class="url" >shiny</a> writes: @erway

同期待laruence
如果写了必买</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/01/03/1225.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>朋友们,新年好.</title>
		<link>http://www.laruence.com/2010/01/01/1216.html</link>
		<comments>http://www.laruence.com/2010/01/01/1216.html#comments</comments>
		<pubDate>Thu, 31 Dec 2009 16:02:35 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[随笔]]></category>
		<category><![CDATA[2010]]></category>
		<category><![CDATA[新年]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1216</guid>
		<description><![CDATA[   2009年就这么过去了, 刚吃了个饭, 和朋友打了会儿球, 回来就2010年了.
   
   呵呵, 祝福大家2010年, 事事顺利, 天天开心.
   
   Rss feed改成全文输出了, 这样订阅我blog的朋友看的就会更方便了. (大家可能需要刷新下reader, 这样之前的文章就可以全文浏览了).
 
  另外, 想着该给blog换个皮肤了. 新年新气象么, :)]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2010/01/01/1216.html"  title="Permanet Link to 朋友们,新年好." >http://www.laruence.com/2010/01/01/1216.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   2009年就这么过去了, 刚吃了个饭, 和朋友打了会儿球, 回来就2010年了.</p>
<p>   呵呵, 祝福大家2010年, 事事顺利, 天天开心.</p>
<p>   Rss feed改成全文输出了, 这样订阅我blog的朋友看的就会更方便了(不过, 大家可能需要刷新下reader, 这样之前的文章就应该可以全文浏览了, 还有个问题, 就是代码高亮的css没发加上去, 谁有好的办法?).</p>
<p>  另外, 想着该给blog换个皮肤了. 新年新气象么, <img src="http://www.laruence.com/wp-includes/images/smilies/icon_smile.gif"  alt=":)"  class="wp-smiley" /> </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
  while (date(&quot;Y&quot;) == &quot;2010&quot;) {
    echo &quot;事事顺利, 工作开心&quot;;
  }
?&gt;
</pre>
</p>
<p><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/2010/01/01/1216.html#comment-2403" >2010/01/01</a>, <a href="http://www.trylife.cn"  rel="external nofollow"  class="url" >trylife</a> writes: 新年快乐</li><li><a href="http://www.laruence.com/2010/01/01/1216.html#comment-2404" >2010/01/01</a>, <a href="http://www.sychen.org"  rel="external nofollow"  class="url" >sychen</a> writes: 一年来看博主的文章，学习不少。 元旦快乐:)</li><li><a href="http://www.laruence.com/2010/01/01/1216.html#comment-2413" >2010/01/04</a>, evan writes: 建议修改下插件，在rss输出的时候把整个的高亮样式内容内联到内容中去比较合适</li><li><a href="http://www.laruence.com/2010/01/01/1216.html#comment-2420" >2010/01/05</a>, silasoni 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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/01/01/1216.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>深入理解PHP原理之变量生命期(一)</title>
		<link>http://www.laruence.com/2009/12/26/1198.html</link>
		<comments>http://www.laruence.com/2009/12/26/1198.html#comments</comments>
		<pubDate>Sat, 26 Dec 2009 13:11:44 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[GET]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[SAPI]]></category>
		<category><![CDATA[variable]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1198</guid>
		<description><![CDATA[对于PHP的中的数据来源, 不外乎有俩种:
<coolcode lang="sh" linenum="off">
1. 来自代码中
2. 来自外部(GET/POST/DB)
</coolcode>
	
	对于代码中的变量(也就是直接量)来说, 变量分配/赋值在编译期, 活跃在执行器, 在请求关闭期被销毁.对于这些变量来说, 使用APC进行Opcode缓存, 则会缓存这部分变量的值. 

	而对于来自外部的变量, 变量分配/赋值在编译器后, 执行期前, 在请求关闭期被销毁,对于这些变量来说, 使用APC进行OpCode缓存, 是不会被缓存的.

	今天就着重关注下外部变量的一个部分,GET来的数据的整个生命周期....]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/12/26/1198.html"  title="Permanet Link to 深入理解PHP原理之变量生命期(一)" >http://www.laruence.com/2009/12/26/1198.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	对于PHP的中的数据来源, 不外乎有俩种:</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. 来自代码中
2. 来自外部(GET/POST/DB)
</pre>
<p>	对于代码中的变量(也就是直接量)来说, 变量分配/赋值在编译期, 活跃在执行器, 在请求关闭期被销毁.对于这些变量来说, 使用APC进行Opcode缓存, 则会缓存这部分变量的值. </p>
<p>	而对于来自外部的变量, 变量分配/赋值在编译器后, 执行期前, 在请求关闭期被销毁,对于这些变量来说, 使用APC进行OpCode缓存, 是不会被缓存的.</p>
<p>	今天就着重关注下外部变量的一个部分,GET来的数据的整个生命周期.</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;">
	GET /index.php?name=laruence&amp;career[]=yahoo&amp;career[]=baidu
</pre>
<p>	而, 在index.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
	$name 	= $_GET['name'];
	$career = $_GET['career']; //array
</pre>
<p>	我们知道, 在最后的执行期, $_GET数组必然包含如下片段:</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;">
	$_GET = array(
		'name'   =&gt; 'laruence',
		'career' =&gt; array(
			'yahoo', 'baidu',
		),
	)
</pre>
<p>	那么, 我们今天就重点关注下, Query String是如何构建成_GET数组的(关于GET变量的生成, 请一并阅读我之前的文章: &#8220;<a href="http://www.laruence.com/2008/11/07/581.html"  target="_blank" >PHP的GET/POST等大变量生成过程</a>&#8220;): </p>
<p>	在请求到来时刻,php_request_startup(定义在main.c)被调用,来做初始化现场. 在这个过程中包括设置超时值,调用各个模块的请求初始化函数. 当然也包括我们关心的, 创建变量环境.</p>
<p>	php_hash_environment根据php.ini中的variables_order来依次初始化各个预定义大变量, 那么对于$_GET来说:</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;">
...
case 'g':
case 'G':
	if (!_gpc_flags[2]) {
		sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
		_gpc_flags[2] = 1;
		if (PG(register_globals)) {
			php_autoglobal_merge(&amp;EG(symbol_table),
				Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC);
		}
	}
break;
...
</pre>
<p>	大体可以看出,这段逻辑,首先通过treat_data来生成变量hash(PG(http_globals)[TRACK_VARS_GET]), 如果打开了auto_register_globals,则再把$_GET数组中的变量加入到符号表中.</p>
<p>	treat_data是属于sapi_module_struct中的一个成员: </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;">
 注意:	本文基于apache2handler方式的sapi, 这个启动过程和之前的文章sapi
原理中的启动过程略有不同, php5通过注册apache2的ap_hook_post_config挂钩,
在apache server启动的时候启动php(php_apache_server_startup,定义在
sapi/apache2hander/sapi_apache2.c中), 在这个函数中调用sapi_startup启动sapi,
继而通过调用php_apache2_startup来注册sapi module struct,
然后调用php_module_startup来初始化PHP, 其中又会初始化ZEND引擎,
以及填充zend_module_struct中的treat_data成员(通过php_startup_sapi_content_types)
为php_default_treat_data
</pre>
<p>	现在回过头来继续看treat_data(也就是php_default_treat_data):</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;">
....
if (arg == PARSE_GET) {     /* GET data */
	c_var = SG(request_info).query_string;
	if (c_var &amp;&amp; *c_var) {
		res = (char *) estrdup(c_var);
		free_buffer = 1;
	} else {
		free_buffer = 0;
	}
} else if (arg == PARSE_COOKIE) {       /* Cookie data */
....
</pre>
<p>	在上面的逻辑中, 给res复制为query_string, SG(request_info)是一个代表了当前请求信息的结构体, 其中query_string是在php_apache_request_ctor中通过复制apache的reqeust_rec结构体中的args而来的. </p>
<p>	对于本文的例子来说, 此时res即为&#8221;name=laruence&#038;career[]=yahoo&#038;career[]=baidu&#8221;, </p>
<p>	继续在treat_data中, 随后的逻辑是:</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;">
var = php_strtok_r(res, separator, &amp;strtok_buf);
...
while (var) {
	val = strchr(var, '=');

	if (arg == PARSE_COOKIE) {
		/* Remove leading spaces from cookie names,
			needed for multi-cookie header where ; can be followed by a space */
		while (isspace(*var)) {
			var++;
		}
		if (var == val || *var == '\0') {
			goto next_cookie;
		}
	}

	if (val) { /* have a value */
		int val_len;
		unsigned int new_val_len;

		*val++ = '\0';
		php_url_decode(var, strlen(var));
		val_len = php_url_decode(val, strlen(val));
		val = estrndup(val, val_len);
		if (sapi_module.input_filter(arg, var, &amp;val, val_len, &amp;new_val_len TSRMLS_CC)) {
			php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
		}
		efree(val);
	} else {
...
</pre>
<p>	首先, 通过php_strtok_r把res根据&#8221;&#038;&#8221;分割成一个一个的&#8221;key=value&#8221;段, 接下来分别为var和val复制为key和value, 注意到这个过程中会分别对var和val做php_url_decode.</p>
<p>	最后通过php_register_variable_safe, 给array_ptr(此时指向PG(http_globals)[TRACK_VARS_GET], 也就是$_GET)添加一个名为var值为val的成员.</p>
<p>	到了这一步, 我们的$_GET数组中, 就包含了如下的成员:</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;">
'name'   =&gt; 'laruence',
'career' =&gt; array(
	'yahoo', 'baidu',
),
</pre>
<p>	未完待续(变量的销毁过程)&#8230;<br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.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_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.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_c.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/2009/12/26/1198.html#comment-2390" >2009/12/26</a>, Robin writes: Hi，麻烦问问，如果想去掉 "[]"，改成
name=laruence&amp;career=yahoo&amp;career=baidu
$_GET数组还要不变，怎么改？

谢谢了。</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2391" >2009/12/26</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @robin 这样的话,最终career的值为baidu</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2396" >2009/12/28</a>, <a href="www.phppan.com"  rel="external nofollow"  class="url" >phppan</a> writes: 在window下用vc看也比较舒服
抚琴居主人有一篇文章有相关介绍
http://www.yanbin.org/blog/commentary-on-php-chap1_1-prep.html</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2397" >2009/12/28</a>, <a href="http://www.metsky.com"  rel="external nofollow"  class="url" >天缘</a> writes: 还没真的没深究过这些源码，佩服博主认真的研究</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2399" >2009/12/28</a>, phpcoder writes: 强悍的博主, 还有点不明白就是数组是怎么parse来的呢?</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2400" >2009/12/28</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @phpcoder 呵呵,就是简单的字符串parse了, 遇到"[]", 就知道是个数组..</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2401" >2009/12/30</a>, eve 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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/12/26/1198.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>服务器搬到国外主机</title>
		<link>http://www.laruence.com/2009/12/17/1182.html</link>
		<comments>http://www.laruence.com/2009/12/17/1182.html#comments</comments>
		<pubDate>Thu, 17 Dec 2009 14:56:03 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[随笔]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1182</guid>
		<description><![CDATA[<p>
    在国内声势浩大的打击非法网站的行动中, 我这个有IPC备案, 无不良内容的良民, 也几次三番的被连坐...

    万般无奈下, 只好谋求把服务器搬离国内..

    鸣谢<a href="http://onemouse.cn">OneMouse.cn</a>友情赞助空间..
 
    有些图片和素材还没法倒过来, 等过俩天国内的服务器能访问了,我在copy过来.

</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/12/17/1182.html"  title="Permanet Link to 服务器搬到国外主机" >http://www.laruence.com/2009/12/17/1182.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
    在国内声势浩大的打击非法网站的行动中, 我这个有IPC备案, 无不良内容的良民, 也几次三番的被连坐&#8230;</p>
<p>    万般无奈下, 只好谋求把服务器搬离国内..</p>
<p>    鸣谢<a href="http://onemouse.cn" >OneMouse.cn</a>友情赞助空间..</p>
<p>    有些图片和素材还没法倒过来, 等过俩天国内的服务器能访问了,我在copy过来.</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/17/1182.html#comment-2371" >2009/12/17</a>, <a href="http://b.freefcw.cn"  rel="external nofollow"  class="url" >巫山霏云</a> writes: 嗯，我也遇到了，很烦恼~~
现在还在找出路中</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2372" >2009/12/17</a>, <a href="http://topsy.com/tb/url4.eu/x2ET"  rel="external nofollow"  class="url" >Tweets that mention 服务器搬到国外主机 » 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by siko, Laruence. Laruence said: 服务器搬到国外主机 http://url4.eu/x2ET [...]</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2373" >2009/12/17</a>, <a href="http://www.chenbin.net"  rel="external nofollow"  class="url" >siko</a> writes: 申请blog友链,在Wave里发过消息给你 。 :)</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2375" >2009/12/18</a>, <a href="http://www.xklog.org"  rel="external nofollow"  class="url" >星空泪</a> writes: 我也被……无话可说，被迫搬家</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2376" >2009/12/18</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 看来被连坐的同学还真多啊...</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2377" >2009/12/18</a>, Venkman writes: 楼主什么时候介绍下无敌穿墙术啊， 现在墙又加了几层， 郁郁啊， 祖国到底是亲妈还是后妈啊</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2378" >2009/12/18</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @siko done~</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2379" >2009/12/18</a>, <a href="http://www.zivee.cn"  rel="external nofollow"  class="url" >zivee</a> writes: 最近是事情确实搞有些心慌</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2380" >2009/12/18</a>, andy writes: 祖国不是亲妈也不是后妈，是他妈</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2418" >2010/01/04</a>, <a href="http://liuqingyan.blogspot.com"  rel="external nofollow"  class="url" >qy</a> writes: sigh...然后domain name白名单。。。然后IP白名单。。。呵呵。。。遁无可遁</li><li><a href="http://www.laruence.com/2009/12/17/1182.html#comment-2419" >2010/01/04</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @qy 唉..大中华局域网.</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/12/17/1182.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>isset和is_null的不同</title>
		<link>http://www.laruence.com/2009/12/09/1180.html</link>
		<comments>http://www.laruence.com/2009/12/09/1180.html#comments</comments>
		<pubDate>Wed, 09 Dec 2009 07:56:44 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[different]]></category>
		<category><![CDATA[isset]]></category>
		<category><![CDATA[is_null]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1180</guid>
		<description><![CDATA[<p>
	今天有人问我isset和is_null啥区别, 
	看手册上讲的话, isset和is_null的功能几乎完全"相反的一样"..
	是不是isset就是一个is_null的相反的别名?
	
	诶, 要说区别, 那还真的是很多~
</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/12/09/1180.html"  title="Permanet Link to isset和is_null的不同" >http://www.laruence.com/2009/12/09/1180.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	今天有人问我isset和is_null啥区别, </p>
<p>	看手册上讲的话, isset和is_null的功能几乎完全&#8221;相反的一样&#8221;..</p>
<p>	是不是isset就是一个is_null的相反的别名?</p>
<p>	诶, 要说区别, 那还真的是很多~
</p>
<p>
<b>一切的不同都是因为: is_null是函数, isset是语句.</b></p>
<p>	isset是语句, 和echo, print一样, 是PHP本身的一种语言结构.</p>
<p>	而is_null是函数, 和我们一般的函数一样, 可以做为可变函数调用.</p>
<p>	你也许会说, 好了,好了,我知道函数和语句的区别, 但到底是TMD什么区别?</p>
<p>	诶, 所谓语句,语言结构, 就是说, 是语言本身支持的语句, 标识符. </p>
<p>	比如, for, foreach, continue 等等, 它们在语法分析的时刻就被&#8221;抹掉&#8221;(逻辑上替代了)了.</p>
<p>	让我们看看isset这个语句在语法分析的过程中, 是如何被&#8221;抹掉&#8221;的.</p>
<pre  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. 首先, 在词法分析的时候, isset会被识别为T_ISSET标识符.

2. 而在语法分析阶段, isset($var)这个指令, 会被分析成一条Opcode:ZEND_ISSET_ISEMPTY_VARS.
</pre>
<p>	你可以理解isset就想C语言里面的宏, 在编译/执行之前已经被展开了.</p>
<p>	因为这个,　所以在表现上,　会有如下的不同:</p>
<p>	因为is_null是函数, 所以它可以通过如下方式调用:</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  = NULL;
$func = &quot;is_null&quot;;
$func($var);
?&gt;
</pre>
<p>	而, isset因为是语句, 所以不能这样调用.</p>
<p>	因为is_null是函数, 所以它可以接受函数返回值做为参数, 而isset不行(当然, 如果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
is_null(intval(&quot;0x45&quot;));
//OK
isset(intval(&quot;0x45&quot;));
//PHP Fatal error:  Can't use function return value in write context
is_null(NULL);
//OK
isset(NULL);
//PHP Parse error:  syntax error
?&gt;
</pre>
<p>	说了这么多isset的缺点了,  说点它的优点吧:</p>
<p>	因为isset是语句, 所以它快!</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
$a=&quot;laruence&quot;:
isset($a);   //用时: 1.15s
is_null($a); //用时: 3.89s
?&gt;
</pre>
<p>	因为isset叫做isset, 所以它在检测未定义变量的时候, 不会产生NOTICE:</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
isset($laruence);
//OK
is_null($laruence);
//PHP Notice:  Undefined variable: laruence
?&gt;
</pre>
<p>	那么, 对于什么时候用isset什么时候用is_null, 我有什么建议呢?</p>
<p>	诶, 我的建议是, 用函数做函数应该做的事情~, 听起来象废话?</p>
<p>	isset => is set? => 变量有没有被赋值(声明)</p>
<p>	is_null => is null? => 变量为NULL么?</p>
<p>	另外,　如果要用is_null,　我建议使用 &#8220;=== NULL&#8221; 来代替,　它不仅语义和is_null一致,　结果一致,　速度还和isset差不多:</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
$a=&quot;laruence&quot;:
isset($a);      //用时: 1.15s
is_null($a);    //用时: 3.88s
$a===NULL;     //用时: 1.22s
?&gt;
</pre>
</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/2009/12/09/1180.html#comment-2355" >2009/12/09</a>, Platinum writes: 让他们直接看手册比较好些

http://www.php.net/manual/en/types.comparisons.php</li><li><a href="http://www.laruence.com/2009/12/09/1180.html#comment-2356" >2009/12/09</a>, <a href="http://www.xiaoxiaozi.com"  rel="external nofollow"  class="url" >simaopig</a> writes: 几乎没用过 is_null  都是 === NULL  不过mysql得用 isnull。。</li><li><a href="http://www.laruence.com/2009/12/09/1180.html#comment-2357" >2009/12/09</a>, <a href="http://willko.javaeye.com"  rel="external nofollow"  class="url" >Willko</a> writes: isset 是指变量是否声明了
isnull 是指变量的值是否为null</li><li><a href="http://www.laruence.com/2009/12/09/1180.html#comment-2358" >2009/12/16</a>, <a href="http://hqlong.com"  rel="external nofollow"  class="url" >hqlong</a> writes: 这风格太黑了，没有以前的视觉效果好</li><li><a href="http://www.laruence.com/2009/12/09/1180.html#comment-2360" >2009/12/16</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 唉,我换了个国外的服务器,国内的老因为封黄网被连坐</li><li><a href="http://www.laruence.com/2009/12/09/1180.html#comment-2395" >2009/12/28</a>, <a href="http://www.simaliu.com/"  rel="external nofollow"  class="url" >simaliu</a> writes: 受教了</li><li><a href="http://www.laruence.com/2009/12/09/1180.html#comment-2450" >2010/02/01</a>, <a href="http://www.phpfamily.cn"  rel="external nofollow"  class="url" >xiaokai</a> writes: 那empty是呢?</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/12/09/1180.html/feed</wfw:commentRss>
		<slash:comments>7</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[core]]></category>
		<category><![CDATA[PHP]]></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>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</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>
</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#comment-2353" >2009/12/06</a>, 玉丰 writes: 最近也在折腾gdb，看了一下这篇文章，（还不会如何去backtrace PHP的运行），呵呵，继续学习。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html#comment-2354" >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#comment-2359" >2009/12/16</a>, kimjxie writes: 在代码末 强制执行session_write_close()也可解决问题</li><li><a href="http://www.laruence.com/2009/12/05/1172.html#comment-2374" >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#comment-2429" >2010/01/15</a>, <a href="http://www.baidu.com"  rel="external nofollow"  class="url" >wakaka</a> writes: 博主的PHP和C的功力实在是国内少有的高手。</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/12/05/1172.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>memory_limit的一个bug</title>
		<link>http://www.laruence.com/2009/11/27/1164.html</link>
		<comments>http://www.laruence.com/2009/11/27/1164.html#comments</comments>
		<pubDate>Fri, 27 Nov 2009 09:40:02 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php bug]]></category>
		<category><![CDATA[php源码分析]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1164</guid>
		<description><![CDATA[<p>
		PHP 5.2x中, 由于错误的选用了zend_atoi, 导致memory_limit不能设置为超过4G的值.

	今天同事分享给我一个问题(thans to yanmi), 一段代码(PHP 5.2.11 Linux/X86_64),设置memory_limit为4096M会导致内存耗尽, 而设置4095M就不会.  奇怪的问题呵.

	那是怎么回事呢?
</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/11/27/1164.html"  title="Permanet Link to memory_limit的一个bug" >http://www.laruence.com/2009/11/27/1164.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	PHP 5.2x中, 由于错误的选用了zend_atoi, 导致memory_limit不能设置为超过4G的值.</p>
<p>	今天同事分享给我一个问题(thans to yanmi), 一段代码(PHP 5.2.11 Linux/X86_64),设置memory_limit为4096M会导致内存耗尽, 而设置4095M就不会.  奇怪的问题呵.</p>
<p>	那是怎么回事呢?
</p>
<p>	问题的原因也很简单, 在PHPSRC/main.c中定义的memory_limit设置项的处理器OnChangeMemoryLimit中, 并没有检测当前的机器字长, 而统一使用了zend_atoi来做为字符串数字化, 这个问题在PHP5.3的版本中已经修正(换成了zend_atol):</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 PHP_INI_MH(OnChangeMemoryLimit)
{
    if (new_value) {
        PG(memory_limit) = zend_atoi(new_value, new_value_length);
    } else {
        PG(memory_limit) = 1&lt;&lt;30;       /* effectively, no limit */
    }
    return zend_set_memory_limit(PG(memory_limit));
}
</pre>
<p>	而, 顾名思义么, atoi是转成整形, 4096M是2的32次方, 发生溢出, 继而环绕成结果为0, zend_atoi代码如下:</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;">
ZEND_API int zend_atoi(const char *str, int str_len)
{
    int retval;

    if (!str_len) {
        str_len = strlen(str);
    }
    retval = strtol(str, NULL, 0);
    if (str_len&gt;0) {
        switch (str[str_len-1]) {
            case 'g':
            case 'G':
                retval *= 1024;
                /* break intentionally missing */
            case 'm':
            case 'M':
                retval *= 1024;
                /* break intentionally missing */
            case 'k':
            case 'K':
                retval *= 1024;
                break;
        }
    }
    return retval;
}
</pre>
<p>最后在zend_set_memory_limit的时候, 会错误的设置memory_limit为mm_heap的blok_size, 那结果就肯定远远小与你所预期的4096M了</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;">
....
 AG(mm_heap)-&gt;limit = (memory_limit &gt;= AG(mm_heap)-&gt;block_size) ? memory_limit : AG(mm_heap)-&gt;block_size;
...
</pre>
<p>最后, 如果是32位的机器,  那确实不算bug,  但现在的机器很多都64了, 最大内存也不再是4GB了, PHP也要与时俱进啊.</p>
<p>PS, 多看别人的代码是有好处的, 今天有学会了intentionally这个单词, ^_^.<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_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/2009/11/27/1164.html#comment-2338" >2009/11/27</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >Anders</a> writes: 真的使用了4G内存？

那我们这些开发机只有512M内存的人怎么活啊?</li><li><a href="http://www.laruence.com/2009/11/27/1164.html#comment-2339" >2009/11/27</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @Anders 呵呵, 现在的服务器都不止4G的内存了..., 不过这个bug确实影响不大..</li><li><a href="http://www.laruence.com/2009/11/27/1164.html#comment-2340" >2009/11/27</a>, fortruth writes: 果然， 今天我也学到了 intentionally 这个单词。 :)</li><li><a href="http://www.laruence.com/2009/11/27/1164.html#comment-2342" >2009/11/27</a>, kevin writes: 4个G内存消耗确实不常见，但有时需要遍历一些数据库操作大数据集的时候还是比较容易碰到的。

分析的不错！另：1&lt;&lt;30是多大？</li><li><a href="http://www.laruence.com/2009/11/27/1164.html#comment-2343" >2009/11/27</a>, kevin writes: 另：1&lt;&lt;30是多大？

--------------------------

应该是pow(2,30)吧,2的30次方。</li><li><a href="http://www.laruence.com/2009/11/27/1164.html#comment-2345" >2009/11/29</a>, <a href="http://www.xklog.org"  rel="external nofollow"  class="url" >星空泪</a> writes: 占用 4G 内存的程序大概需要优化了……</li><li><a href="http://www.laruence.com/2009/11/27/1164.html#comment-2348" >2009/12/02</a>, Anonymous writes: 脚本语言估计是不会 要 4G 内存的了。</li><li><a href="http://www.laruence.com/2009/11/27/1164.html#comment-2349" >2009/12/02</a>, laruence writes: @Anonymous 恩, 这个只是就问题而说问题, 再说,设置成4096,不代表就要用4096么, ;_)</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/11/27/1164.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>automake,autoconf使用详解</title>
		<link>http://www.laruence.com/2009/11/18/1154.html</link>
		<comments>http://www.laruence.com/2009/11/18/1154.html#comments</comments>
		<pubDate>Wed, 18 Nov 2009 08:37:50 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[GNU C/C++]]></category>
		<category><![CDATA[转载]]></category>
		<category><![CDATA[aclocal]]></category>
		<category><![CDATA[autoconf]]></category>
		<category><![CDATA[automake]]></category>
		<category><![CDATA[configure]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1154</guid>
		<description><![CDATA[    作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实是很方便.一般情况下,大家都是手工写一个简单Makefile,如果要想写出一个符合自由软件惯例的Makefile就不那么容易了.

    在本文中,将给大家介绍如何使用autoconf和automake两个工具来帮助我们自动地生成符合自由软件惯例的 Makefile,这样就可以象常见的 GNU程序一样,只要使用"./configure","make","make instal"就可以把程序安装到Linux系统中去了.

    这将特别适合想做开放源代码软件的程序开发人员,又或如果你只是自己写些小的Toy程序,那么这个文章对你也会有很大的帮助.
转自:<a href="http://www.linuxcomputer.cn/jishuwendang/xinshourumen/200902/03-3029.html">http://www.linuxcomputer.cn/jishuwendang/xinshourumen/200902/03-3029.html</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/2009/11/18/1154.html"  title="Permanet Link to automake,autoconf使用详解" >http://www.laruence.com/2009/11/18/1154.html</a></li>
<li>文章转自: <a href="http://www.linuxcomputer.cn/jishuwendang/xinshourumen/200902/03-3029.html" >http://www.linuxcomputer.cn/</a></li>
</ul></div>
<p>	作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实是很方便.一般情况下,大家都是手工写一个简单Makefile,如果要想写出一个符合自由软件惯例的Makefile就不那么容易了.</p>
<p>	在本文中,将给大家介绍如何使用autoconf和automake两个工具来帮助我们自动地生成符合自由软件惯例的 Makefile,这样就可以象常见的 GNU程序一样,只要使用&#8221;./configure&#8221;,&#8221;make&#8221;,&#8221;make instal&#8221;就可以把程序安装到Linux系统中去了.</p>
<p>       这将特别适合想做开放源代码软件的程序开发人员,又或如果你只是自己写些小的Toy程序,那么这个文章对你也会有很大的帮助.<br/>
　<br/>
<h3>一.Makefile介绍</h3>
<p>　　Makefile是用于自动编译和链接的 ,一个工程有很多文件组成,每一个文件的改变都会导致工程的重新链接,但是不是 所有的文件都需要重新编译,Makefile中纪录有文件的信息,在 make时会决定在链接的时候需要重新编译哪些文件.<br/>
　<br/>
　	Makefile的宗旨就是 ：让编译器知道要编译一个文件需要依赖其他的 哪些文件.当那些依赖文件有了改变,编译器会自动的发现最终的生成文件已经过时,而重新编译相应的 模块.<br/>
　　<br/>
	Makefile的 基本结构不是 很复杂,但当一个程序开发人员开始写Makefile时,经常会怀疑自己写的 是 否符合惯例,而且自己写的 Makefile经常和自己的 开发环境相关联,当系统环境变量或路径发生了变化后,Makefile可能还要跟着修改.这样就造成了手工书写Makefile的 诸多问题,automake恰好能很好地帮助我们解决这些问题.<br/>
　　<br/>
	使用automake,程序开发人员只需要写一些简单的 含有预定义宏的 文件,由autoconf根据一个宏文件生成configure,由automake根据另一个宏文件生成Makefile.in,再使用configure依据Makefile.in来生成一个符合惯例的 Makefile.下面我们将详细介绍Makefile的 automake生成方法.<br/>
　　</p>
<h3>二.使用的 环境</h3>
<p>　　本文所提到的 程序是 基于Linux发行版本：Fedora Core release 1,它包含了我们要用到的 autoconf,automake.</p>
<p>　　<br/>
<h3>三.从helloworld入手</h3>
<p>　　我们从大家最常使用的 例子程序helloworld开始.</p>
<p>　　下面的 过程如果简单地说来就是 ：</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;">
　　　helloworld.c
　　　configure.in
　　　Makefile.am
</pre>
<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;">
aclocal; autoconf; automake --add-missing; ./configure; make; ./helloworld
</pre>
<p>　　就可以看到Makefile被产生出来,而且可以将helloworld.c编译通过.</p>
<p>　　很简单吧,几条命令就可以做出一个符合惯例的 Makefile,感觉如何呀.</p>
<p>　　<b>现在 开始介绍详细的 过程：</b></p>
<p>　　1.建目录</p>
<p>　　在 你的 工作目录下建一个helloworld目录,我们用它来存放helloworld程序及相关文件,如在 /home/my/build下：</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;">
$ mkdir helloword
$ cd helloworld
</pre>
<p>　　2. helloworld.c</p>
<p>　　然后用你自己最喜欢的 编辑器写一个hellowrold.c文件,如命令：vi helloworld.c.使用下面的 代码作为helloworld.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;">
#include &lt;stdio.h&gt;
int main(int argc, char** argv){
	printf(&quot;%s&quot;, 'Hello, Linux World!\n&quot;);
	return 0;
}
</pre>
<p>　　完成后保存退出.<br/>
　　现在 在 helloworld目录下就应该有一个你自己写的 helloworld.c了.</p>
<p>　　3.生成configure</p>
<p>　　我们使用autoscan命令来帮助我们根据目录下的 源代码生成一个configure.in的 模板文件.<br/>
　　命令：</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;">
$ autoscan
$ ls
configure.scan helloworld.c
</pre>
<p>　　执行后在 hellowrold目录下会生成一个文件：configure.scan,我们可以拿它作为configure.in的 蓝本.<br/>
　　现在 将configure.scan改名为configure.in,并且编辑它,按下面的 内容修改,去掉无关的 语句：</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;">
==========================configure.in内容开始=========================================
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_INIT(helloworld.c)
AM_INIT_AUTOMAKE(helloworld, 1.0)
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT(Makefile)
==========================configure.in内容结束=========================================
</pre>
<p>　　然后执行命令aclocal和autoconf,分别会产生aclocal.m4及configure两个文件：</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;">
$ aclocal
$ls
aclocal.m4 configure.in helloworld.c
$ autoconf
$ ls
aclocal.m4 autom4te.cache configure configure.in helloworld.c
</pre>
<p>　　大家可以看到configure.in内容是 一些宏定义,这些宏经autoconf处理后会变成检查系统特性.环境变量.软件必须的 参数的 shell脚本.</p>
<p>　　autoconf 是 用来生成自动配置软件源代码脚本（configure）的 工具.configure脚本能独立于autoconf运行,且在 运行的 过程中,不需要用户的 干预.</p>
<p>　　要生成configure文件,你必须告诉autoconf如何找到你所用的 宏.方式是 使用aclocal程序来生成你的 aclocal.m4.</p>
<p>　　aclocal根据configure.in文件的 内容,自动生成aclocal.m4文件.aclocal是 一个perl 脚本程序,它的 定义是 ：&#8221;aclocal &#8211; create aclocal.m4 by scanning configure.ac&#8221;.</p>
<p>　　autoconf从configure.in这个列举编译软件时所需要各种参数的 模板文件中创建configure.</p>
<p>　　autoconf需要GNU m4宏处理器来处理aclocal.m4,生成configure脚本.</p>
<p>　　m4是 一个宏处理器.将输入拷贝到输出,同时将宏展开.宏可以是 内嵌的 ,也可以是 用户定义的 .除了可以展开宏,m4还有一些内建的 函数,用来引用文件,执行命令,整数运算,文本操作,循环等.m4既可以作为编译器的 前端,也可以单独作为一个宏处理器.</p>
<p>4.新建Makefile.am<br/>
　　新建Makefile.am文件,命令：</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;">
$ vi Makefile.am
　　内容如下:
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=helloworld
helloworld_SOURCES=helloworld.c
</pre>
<p>　　automake会根据你写的 Makefile.am来自动生成Makefile.in.</p>
<p>　　Makefile.am中定义的 宏和目标,会指导automake生成指定的 代码.例如,宏bin_PROGRAMS将导致编译和连接的 目标被生成.<br/>
　　5.运行automake:</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;">
$ automake --add-missing
configure.in: installing `./install-sh'
configure.in: installing `./mkinstalldirs'
configure.in: installing `./missing'
Makefile.am: installing `./depcomp'
</pre>
<p>　　automake会根据Makefile.am文件产生一些文件,包含最重要的 Makefile.in.</p>
<p>　　6.执行configure生成Makefile</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;">
$./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking for C compiler default output... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ANSI C... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands
$ ls -l Makefile
-rw-rw-r-- 1 yutao yutao 15035 Oct 15 10:40 Makefile
</pre>
<p>你可以看到,此时Makefile已经产生出来了.</p>
<p>7.使用Makefile编译代码</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;">
$make
if gcc -DPACKAGE_NAME=\&quot;FULL-PACKAGE-NAME\&quot; -DPACKAGE_TARNAME=\&quot;full-package-name\&quot; -DPACKAGE_VERSION=\&quot;VERSION\&quot; -DPACKAGE_STRING=\&quot;FULL-PACKAGE-NAME\ VERSION\&quot; -DPACKAGE_BUGREPORT=\&quot;BUG-REPORT-ADDRESS\&quot; -DPACKAGE=\&quot;helloworld\&quot; -DVERSION=\&quot;1.0\&quot; -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1  -I. -I.     -g -O2 -MT helloworld.o -MD -MP -MF &quot;.deps/helloworld.Tpo&quot; -c -o helloworld.o helloworld.c; \
then mv -f &quot;.deps/helloworld.Tpo&quot; &quot;.deps/helloworld.Po&quot;; else rm -f &quot;.deps/helloworld.Tpo&quot;; exit 1; fi
gcc  -g -O2   -o helloworld  helloworld.o
</pre>
<p>　　运行helloworld</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;">
$ ./helloworld
Hello, Linux World!
</pre>
<p>　　这样helloworld就编译出来了,你如果按上面的 步骤来做的 话,应该也会很容易地编译出正确的 helloworld文件.你还可以试着使用一些其他的 make命令,如make clean,make install,make dist,看看它们会给你什么样的 效果.感觉如何？自己也能写出这么专业的 Makefile,老板一定会对你刮目相看.</p>
<h3>四.深入浅出</h3>
<p>　　针对上面提到的 各个命令,我们再做些详细的 介绍.</p>
<pre  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. autoscan
　　autoscan是 用来扫描源代码目录生成configure.scan文件的 .autoscan
可以用目录名做为参数,但如果你不使用参数的 话,那么autoscan将认为使用的是当前目录.
autoscan将扫描你所指定目录中的 源文件,并创建configure.scan文件.
　　2. configure.scan
　　configure.scan包含了系统配置的 基本选项,里面都是 一些宏定义.我们需要将它改名为
configure.in
　　3. aclocal
　　aclocal是 一个perl 脚本程序.aclocal根据configure.in文件的 内容
,自动生成aclocal.m4文件.aclocal的 定义是 ："aclocal - create
aclocal.m4 by scanning configure.ac".
　　4. autoconf
　　autoconf是 用来产生configure文件的 .configure是 一个脚本,它能设置
源程序来适应各种不同的操作系统平台,并且根据不同的 系统来产生合适的 Makefile,从而可以使
你的源代码能在不同的操作系统平台上被编译出来.
　　configure.in文件的 内容是 一些宏,这些宏经过autoconf 处理后会变成检查系统
特性.环境变量.软件必须的 参数的 shell脚本.configure.in文件中的 宏的 顺序并没
有规定,但是 你必须在 所有宏的 最前面和最后面分别加上AC_INIT宏和AC_OUTPUT宏.
　　在 configure.ini中：
　　#号表示注释,这个宏后面的 内容将被忽略.
　　AC_INIT(FILE)
　　这个宏用来检查源代码所在 的 路径.
AM_INIT_AUTOMAKE(PACKAGE, VERSION)
　　 这个宏是 必须的 ,它描述了我们将要生成的 软件包的 名字及其版本号：PACKAGE是软件包
的名字,VERSION是 版本号.当你使用make dist命令时,它会给你生成一个类似
helloworld-1.0.tar.gz的 软件发行包,其中就有对应的 软件包的 名字和版本号.
AC_PROG_CC
　　这个宏将检查系统所用的 C编译器.
AC_OUTPUT(FILE)
　　这个宏是 我们要输出的 Makefile的 名字.
　　我们在 使用automake时,实际上还需要用到其他的 一些宏,但我们可以用aclocal 来帮
我们自动产生.执行aclocal后我们会得到aclocal.m4文件.
　　产生了configure.in和aclocal.m4 两个宏文件后,我们就可以使用autocon
f来产生configure文件了.
　　5. Makefile.am
　　Makefile.am是 用来生成Makefile.in的 ,需要你手工书写.Makefile.
am中定义了一些内容：
AUTOMAKE_OPTIONS
　　这个是 automake的 选项.在 执行automake时,它会检查目录下是 否存在 标准
GNU软件包中应具备的各种文件,例如AUTHORS.ChangeLog.NEWS等文件.
我们将其设置成foreign时,automake会改用一般软件包的 标准来检查.
bin_PROGRAMS
　　这个是 指定我们所要产生的 可执行文件的 文件名.如果你要产生多个可执行文件,
那么在各个名字间用空格隔开.
helloworld_SOURCES
　　这个是 指定产生"helloworld"时所需要的 源代码.如果它用到了多个源文件,
那么请使用空格符号将它们隔开.比如需要helloworld.h,helloworld.c那么请写成:
helloworld_SOURCES= helloworld.h helloworld.c.
　　如果你在 bin_PROGRAMS定义了多个可执行文件,则对应每个可执行文件都要定义相对的
filename_SOURCES.
　　6. automake
　　我们使用automake --add-missing来产生Makefile.in.
　　选项--add-missing的 定义是 "add missing standard files
 to package",它会让automake加入一个标准的 软件包所必须的 一些文件.
　　我们用automake产生出来的 Makefile.in文件是 符合GNU Makefile惯例
的 ,接下来我们只要执行configure这个shell 脚本就可以产生合适的 Makefile 文
件了.
　　7. Makefile
　　在 符合GNU Makefiel惯例的 Makefile中,包含了一些基本的 预先定义的 操作：

make
　　根据Makefile编译源代码,连接,生成目标文件,可执行文件.
make clean
　　清除上次的 make命令所产生的 object文件（后缀为".o"的 文件）及可执行文件.
make install
　　将编译成功的 可执行文件安装到系统目录中,一般为/usr/local/bin目录.
make dist
　　产生发布软件包文件（即distribution package）.这个命令将会将可执行文件及相关
文件打包成一个tar.gz压缩的 文件用来作为发布软件的 软件包.
　　它会在 当前目录下生成一个名字类似"PACKAGE-VERSION.tar.gz"的 文件.PA
CKAGE和VERSION,是 我们在 configure.in中定义的 AM_INIT_AUTOM
AKE(PACKAGE, VERSION).
make distcheck
　　生成发布软件包并对其进行测试检查,以确定发布包的正确性.
</pre>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.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_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.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/11/18/1154.html#comment-2444" >2010/01/25</a>, Nathan writes: That's awesome!
It would be great help for me.</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/11/18/1154.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>分割GBK中文遭遇乱码的解决</title>
		<link>http://www.laruence.com/2009/11/16/1147.html</link>
		<comments>http://www.laruence.com/2009/11/16/1147.html#comments</comments>
		<pubDate>Mon, 16 Nov 2009 07:57:12 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[随笔]]></category>
		<category><![CDATA[explode]]></category>
		<category><![CDATA[gbk]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1147</guid>
		<description><![CDATA[今天有朋友提到一个问题, 类似如下的字符串(GBK), explode不能得到正确结果:
<coolcode lang="php" linenum="off">
$result = explode("&#124;", "滕华弢&#124;海青"); //(插一句, 蜗居最近很火啊)
</coolcode>
究其原因, 对于"弢"字(读tao,不认识没关系,我也不认识), 因为他的GBK编码值为: 8f7c, 不巧的是, "&#124;"的ASCII值也是7c.

这样的问题, 还有很多...]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/11/16/1147.html"  title="Permanet Link to 分割GBK中文遭遇乱码的解决" >http://www.laruence.com/2009/11/16/1147.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>今天有朋友提到一个问题, 类似如下的字符串(GBK), explode不能得到正确结果:</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;">
$result = explode(&quot;|&quot;, &quot;滕华弢|海青&quot;); //(插一句, 蜗居最近很火啊)
</pre>
<p>究其原因, 对于&#8221;弢&#8221;字(读tao,不认识没关系,我也不认识), 因为他的GBK编码值为: 8f7c, 不巧的是, &#8220;|&#8221;的ASCII值也是7c.</p>
<p>这样的问题, 还有很多 : 因为GBK编码的编码范围是: 0&#215;8140-0xfefe, 所以, 理论上来说, 任何低字节是7c的字都会有这个问题, 比如:</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;">
倈(827c), 億(837c), 眧(b17c), 鍇(e57c).......等等等等.
</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;">
第一, 可以采用转码到utf8, 然后explode, 再转回来, 这是比较麻烦的方法.

第二, 我们可以采用正则拿&quot;匹配出&quot;来代替&quot;分离出&quot;:
    preg_match_all(&quot;/([\x81-\xfe][\x40-\xfe])+/&quot;, $gbk_str, $matches);//写死编码值
</pre>
<p>这样, $matches中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_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/2009/11/16/1147.html#comment-2317" >2009/11/16</a>, <a href="http://www.sina.com.cn"  rel="external nofollow"  class="url" >zorro</a> writes: 用了第一种方法  谢谢鸟哥</li><li><a href="http://www.laruence.com/2009/11/16/1147.html#comment-2318" >2009/11/16</a>, <a href="http://www.xiaoxiaozi.com"  rel="external nofollow"  class="url" >simaopig</a> writes: GBK编码：0×8040-0xffff, 
正则：[\\\\x80-\\\\xff][\\\\x40-\\\\xff]+
这样的组合就是前两位的80-ff结合后两位40-ff之间的所有字符，+表示出现一次或多次，贪婪模式，所以就是按非汉字分隔
赞，相当帅了，鸟哥，我爱死你了。</li><li><a href="http://www.laruence.com/2009/11/16/1147.html#comment-2319" >2009/11/16</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @simaopig  ...你的头像双人照.....</li><li><a href="http://www.laruence.com/2009/11/16/1147.html#comment-2320" >2009/11/16</a>, cody writes: 还是第一种方法有通用性，第二种方法除了中文外要考虑其他字符太多。</li><li><a href="http://www.laruence.com/2009/11/16/1147.html#comment-2322" >2009/11/17</a>, PeterYu writes: 如果不是gbk，倒可以使用mb_split来分割。
可惜mb的正则库只接受gb2312,不接受cp936即gbk.
UTF8也能直接使用。这时就体现出UTF8的好处了。。</li><li><a href="http://www.laruence.com/2009/11/16/1147.html#comment-2323" >2009/11/17</a>, gently writes: 吼吼，可以把分割符换了，例如："&gt;|&lt;"，即用3个字符来分隔</li><li><a href="http://www.laruence.com/2009/11/16/1147.html#comment-2324" >2009/11/17</a>, <a href="http://b.freefcw.cn"  rel="external nofollow"  class="url" >巫山霏云</a> writes: 我觉得还是utf-8比较靠谱一点</li><li><a href="http://www.laruence.com/2009/11/16/1147.html#comment-2325" >2009/11/19</a>, 关注者 writes: 弱弱的问一句：如何得到汉字的编码，呵呵</li><li><a href="http://www.laruence.com/2009/11/16/1147.html#comment-2326" >2009/11/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @关注着 1,查编码表 2,用16位编辑器, 3,在php中使用unpack, 4, 在js中使用charCodeAt .... 等等等等</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/11/16/1147.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Nginx(PHP/fastcgi)的PATH_INFO问题</title>
		<link>http://www.laruence.com/2009/11/13/1138.html</link>
		<comments>http://www.laruence.com/2009/11/13/1138.html#comments</comments>
		<pubDate>Fri, 13 Nov 2009 06:48:15 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[Linux/Unix]]></category>
		<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[path_info]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1138</guid>
		<description><![CDATA[PATH_INFO是一个CGI 1.1的标准，经常用来做为传参载体.

在Apache中, 当不加配置的时候, 对于PHP脚本, AcceptPathInfo是默认接受的, 也就是说:


如果在服务器在存在一个/laruence/info.php

那么, 对于如下请求, Apache都接受:
<coolcode lang="bash" linenum="off">
/laruence/info.php/dummy
/laruence/info.php/pathinfo
</coolcode>
而对于Nginx下, 默认Nginx是不支持PATH INFO的, 也就是说, 对于上面的访问, 会是404, 提示找不到文件出错.]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/11/13/1138.html"  title="Permanet Link to Nginx(PHP/fastcgi)的PATH_INFO问题" >http://www.laruence.com/2009/11/13/1138.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>PATH_INFO是一个CGI 1.1的标准，经常用来做为传参载体. </p>
<p>比如, 我们可以使用PATH_INFO来代替Rewrite来实现伪静态页面, 另外不少PHP框架也使用PATH_INFO来作为路由载体.</p>
<p>在Apache中, 当不加配置的时候, 对于PHP脚本, AcceptPathInfo是默认接受的, 也就是说:</p>
<p>如果在服务器在存在一个/laruence/index.php</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;">
/laruence/index.php/dummy
/laruence/dummy
</pre>
<p>Apache都接受,  都会认为是对info.php的访问, 并会设置PATH_INFO为dummy</p>
<p>而对于Nginx下, 是不支持PATH INFO的, 也就是它不会默认设置PATH_INFO. </p>
<p>而因为默认的配置文件对PHP的支持只是很基础的, 所以对于默认配置来说对于上面的访问也会是404, 提示找不到文件出错.</p>
<p>这对于一些使用PATH_INFO来传递关键信息的PHP框架来说(比如Kohana, Thinkphp), 简直是致命的.</p>
<p>对于这个问题, 一般来说有俩种解决方法, 第一种就是使用rewrite, 但是这个方法的缺点也是很明显的, 需要把PATH_INFO转换成Query String. 此处就不说明这种方法了~</p>
<p>而, 第二种方法就是我今天要提的, 模拟PATH_INFO:</p>
<p>首先 , 我们知道在Nginx中, 是通过对文件名的扩展名匹配, 来决定是否要交给php cgi服务器去解释的. 在nginx.conf中一般都有如下的默认配置段:</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;">
location ~ .php$ {
	fastcgi_index  index.php;
	fastcgi_pass   127.0.0.1:9000;
	include        fastcgi_params;
}
</pre>
<p>所以,对于形如/laruence/info.php/pathinfo这样的文件路径, Nginx是不会正确的交给php cgi服务器的. 所以我们需要改写这段配置为:</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;">
	location ~ .php {//片段匹配
	fastcgi_index  index.php;
	fastcgi_pass   127.0.0.1:9000;
	include        fastcgi_params;
}
</pre>
<p>现在, 脚本路径已经交由PHP自己处理了. 那怎么增加PATH_INFO呢?</p>
<p>首先, 我们需要打开PHP中cgi.fix_pathinfo配置项, 打开这个配置项以后, PHP会去根据CGI规范来检查SCRIPT_FILENAME中那部分是访问脚本和PATH_INFO(<a href="http://cn.php.net/manual/en/ini.core.php" >ini配置解释</a>), 并根据SCRIPT_NAME来修改PATH_INFO(和PATH_TRANSLATED)为正确的值(其实也就是说明, PHP最初对CGI 1.1的支持并不到位)</p>
<p>然后, 就只要添加一个FASTCGI_PARAM项就好了:</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;">
location ~ .php {
	fastcgi_index  index.php;
	fastcgi_pass   127.0.0.1:9000;
	include        fastcgi_params;
	fastcgi_param  PATH_INFO $fastcgi_script_name;
}
</pre>
<p>现在试试吧&#8230;</p>
<p>btw: 当然, 上面的解决方法, 把对路径的分析交给了PHP去处理, 网上也有朋友给出了另外一种配置方法, 这个方法是由Nginx来分析路径(也就不需要fix_pathinfo):</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;">
location ~ \.php
{
	fastcgi_index index.php;
	fastcgi_pass 127.0.0.1:9000;
	include      fastcgi_params;
	set $path_info &quot;&quot;;
	set $real_script_name $fastcgi_script_name;
	if ($fastcgi_script_name ~ &quot;^(.+?\.php)(/.+)$&quot;) {
	set $real_script_name $1;
	set $path_info $2;
}
fastcgi_param SCRIPT_FILENAME /var/html/$real_script_name;
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
}
</pre>
<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_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.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/2009/11/13/1138.html#comment-2307" >2009/11/13</a>, <a href="http://www.zvv.cn"  rel="external nofollow"  class="url" >zwws</a> writes: 按上文修改conf后
访问/p.php/
得到的结果是
/p.php/index.php</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2308" >2009/11/13</a>, <a href="http://phpv.net"  rel="external nofollow"  class="url" >esayr</a> writes: 得到的结果
/p.php/index.php

是正常的.相当于一个文件夹.

文章转载请求.:)</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2309" >2009/11/13</a>, <a href="http://www.zvv.cn"  rel="external nofollow"  class="url" >zwws</a> writes: 纠正下, 我访问/p.php/
PATH_INFO是/index.php
访问/p.php/aa
PATH_INFO是/aa
不明白了</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2310" >2009/11/13</a>, <a href="http://www.zvv.cn"  rel="external nofollow"  class="url" >zwws</a> writes: @esayr
大概理解你的意思了, 可是问题是apache下访问/p.php/返回的是/
难道只能通过程序去"智能"判断么?
能否通过调整nginx的配置来解决呢?</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2311" >2009/11/14</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @zwws 我已补充自己判断的配置, ;)</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2313" >2009/11/15</a>, <a href="http://www.zvv.cn"  rel="external nofollow"  class="url" >zwws</a> writes: 反复折腾了三次到现在, 结果依旧如下:

访问http://localhost/p.php/

PATH_INFO 为 /index.php
PHP_SELF 为 /p.php/index.php


配置文件和http://localhost/p.php/的phpinfo()截图放在这了:

http://www.zvv.cn/nginx_conf.rar</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2314" >2009/11/15</a>, <a href="http://www.zvv.cn"  rel="external nofollow"  class="url" >zwws</a> writes: 有空的话帮忙瞅瞅, thanks. :)</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2315" >2009/11/15</a>, <a href="http://www.zvv.cn"  rel="external nofollow"  class="url" >zwws</a> writes: 解决了.

http://www.zvv.cn/blog/show-110-1.html</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2316" >2009/11/16</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @zwws con~~ ;)</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2321" >2009/11/17</a>, <a href="http://deving.cn"  rel="external nofollow"  class="url" >Torr</a> writes: 好文章，转载到 deving.cn 了，希望可以和更多的人分享</li><li><a href="http://www.laruence.com/2009/11/13/1138.html#comment-2438" >2010/01/20</a>, <a href="http://www.laruence.com/2010/01/20/1247.html"  rel="external nofollow"  class="url" >Nginx/PHP Fastcgi PATH_INFO的一个问题 | 风雪之隅</a> writes: [...] 通过在nginx.conf中模拟PATH_INFO的方法会有一个bug. 那就是PATH_INFO不会被urldecode. [...]</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/11/13/1138.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>提升PHP性能之改变Zend引擎分发方式</title>
		<link>http://www.laruence.com/2009/10/15/1131.html</link>
		<comments>http://www.laruence.com/2009/10/15/1131.html#comments</comments>
		<pubDate>Thu, 15 Oct 2009 08:21:19 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php源码分析]]></category>
		<category><![CDATA[ZE]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[效率]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1131</guid>
		<description><![CDATA[	从PHP5.1开始,PHP提供了用户对Zend VM执行分发方式的选择接口. 

	之前的文章中, 我也提过这方面的内容, Zend虚拟机在执行的时候, 对于编译生成的op_array中的每一条opline的opcode都会分发到相应的处理器(zend_vm_def.h定义)执行, 而按照分发的方式不同, 分发过程可以分为CALL, SWITCH, 和GOTO三种类型.

默认是CALL方式, 也就是所有的opcode处理器都定义为函数, 然后虚拟机调用. 这种方式是传统的方式, 也一般被认为是最稳定的方式.
	
SWITCH方式和GOTO方式则和其命名的意义相同, 分别通过switch和goto来分发.官方给出的描述说GOTO方式最快.

   那么如果使用GOTO方式, 效率上到底能提高多少呢? 今天我就分别使用各种方式来测试一番:]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/10/15/1131.html"  title="Permanet Link to 提升PHP性能之改变Zend引擎分发方式" >http://www.laruence.com/2009/10/15/1131.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	从PHP5.1开始,PHP提供了用户对Zend VM执行分发方式的选择接口. </p>
<p>	之前的文章中, 我也提过这方面的内容, Zend虚拟机在执行的时候, 对于编译生成的op_array中的每一条opline的opcode都会分发到相应的处理器(zend_vm_def.h定义)执行, 而按照分发的方式不同, 分发过程可以分为CALL, SWITCH, 和GOTO三种类型.</p>
<p>	默认是CALL方式, 也就是所有的opcode处理器都定义为函数, 然后虚拟机调用. 这种方式是传统的方式, 也一般被认为是最稳定的方式.</p>
<p>	SWITCH方式和GOTO方式则和其命名的意义相同, 分别通过switch和goto来分发.</p>
<p>	官方给出的描述是:</p>
<blockquote><p>
<span><br/>
CALL &#8211; Uses function handlers for opcodes<br/>
SWITCH &#8211; Uses switch() statement for opcode dispatch<br/>
GOTO &#8211; Uses goto for opcode dispatch (threaded opcodes architecture)<br/>
GOTO is usually (depends on CPU and compiler) faster than SWITCH, which<br/>
tends to be slightly faster than CALL.<br/>
CALL is default because it doesn&#8217;t take very long to compile as opposed<br/>
to the other two and in general the speed is quite close to the others.<br/>
</span>
</p></blockquote>
<p>   那么如果使用GOTO方式, 效率上到底能提高多少呢?</p>
<p>   今天我就分别使用各种方式来测试一番, 测试脚本<a href="http://www.laruence.com/2009/10/15/1131.html#bench" >bench.php</a>.</p>
<p>   第一点被证明的就是, 官方说的GOTO方式编译耗时显著高于其他俩种方式, 我一开始在虚拟机上编译, 每次都Hangup(囧), 最后只好换了个强劲点的物理机, 大约3分钟后, 编译成功..</p>
<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;">
PHP 5.3.0   Linux
AMD Opteron(tm) Processor 270(2G) X 4  6G Memory
</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;">
./configure --with-zend-vm=CALL/GOTO/SWITCH
</pre>
<p>  测试结果如下(都是三次取中值):</p>
<p>CALL方式:</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;">
laruence@dev01.tc$ sapi/cli/php bench.php
simple             0.358
simplecall         0.418
simpleucall        0.405
simpleudcall       0.424
mandel             1.011
mandel2            1.238
ackermann(7)       0.375
ary(50000)         0.083
ary2(50000)        0.075
ary3(2000)         0.561
fibo(30)           1.156
hash1(50000)       0.114
hash2(500)         0.091
heapsort(20000)    0.270
matrix(20)         0.276
nestedloop(12)     0.599
sieve(30)          0.350
strcat(200000)     0.039
------------------------
Total              7.844
</pre>
<p>SWITCH方式:</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;">
laruence@dev01.tc$ sapi/cli/php bench.php
simple             0.393
simplecall         0.414
simpleucall        0.424
simpleudcall       0.445
mandel             1.007
mandel2            1.254
ackermann(7)       0.392
ary(50000)         0.084
ary2(50000)        0.073
ary3(2000)         0.593
fibo(30)           1.185
hash1(50000)       0.120
hash2(500)         0.092
heapsort(20000)    0.285
matrix(20)         0.295
nestedloop(12)     0.678
sieve(30)          0.359
strcat(200000)     0.042
------------------------
Total              8.138
</pre>
<p>GOTO方式 :</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;">
laruence@dev01.tc$ sapi/cli/php bench.php
simple             0.306
simplecall         0.373
simpleucall        0.369
simpleudcall       0.385
mandel             0.879
mandel2            1.132
ackermann(7)       0.356
ary(50000)         0.081
ary2(50000)        0.073
ary3(2000)         0.525
fibo(30)           1.043
hash1(50000)       0.111
hash2(500)         0.088
heapsort(20000)    0.247
matrix(20)         0.247
nestedloop(12)     0.519
sieve(30)          0.331
strcat(200000)     0.037
------------------------
Total              7.103
</pre>
<p>可见, <b>GOTO方式最快, SWITCH方式最慢.</b>和官方的描述稍有不符.</p>
<p>GOTO方式比其默认的CALL方式, 性能提升还是比较明显的. </p>
<p>所以, 如果你希望让PHP发挥到机制, 改变Zend VM的分发方式, 也可以做为一个考虑因素.
</p>
<p>
附:</p>
<p>使用GOTO方式的configure选项:</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;">
--with-zend-vm=GOTO
</pre>
<p>也可以在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;">
php zend_vm_gen.php --with-vm-kind=[CALL|GOTO|SWITH]
</pre>
<p><a name="bench" > </a>测试脚本bench.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
/**
 * PHP Perf Bench Test Script
 */
function simple() {
  $a = 0;
  for ($i = 0; $i &lt; 1000000; $i++)
    $a++;

  $thisisanotherlongname = 0;
  for ($thisisalongname = 0; $thisisalongname &lt; 1000000; $thisisalongname++)
    $thisisanotherlongname++;
}

/****/

function simplecall() {
  for ($i = 0; $i &lt; 1000000; $i++)
    strlen(&quot;hallo&quot;);
}

/****/

function hallo($a) {
}

function simpleucall() {
  for ($i = 0; $i &lt; 1000000; $i++)
    hallo(&quot;hallo&quot;);
}

/****/

function simpleudcall() {
  for ($i = 0; $i &lt; 1000000; $i++)
    hallo2(&quot;hallo&quot;);
}

function hallo2($a) {
}

/****/

function mandel() {
  $w1=50;
  $h1=150;
  $recen=-.45;
  $imcen=0.0;
  $r=0.7;
  $s=0;  $rec=0;  $imc=0;  $re=0;  $im=0;  $re2=0;  $im2=0;
  $x=0;  $y=0;  $w2=0;  $h2=0;  $color=0;
  $s=2*$r/$w1;
  $w2=40;
  $h2=12;
  for ($y=0 ; $y&lt;=$w1; $y=$y+1) {
    $imc=$s*($y-$h2)+$imcen;
    for ($x=0 ; $x&lt;=$h1; $x=$x+1) {
      $rec=$s*($x-$w2)+$recen;
      $re=$rec;
      $im=$imc;
      $color=1000;
      $re2=$re*$re;
      $im2=$im*$im;
      while( ((($re2+$im2)&lt;1000000) &amp;&amp; $color&gt;0)) {
        $im=$re*$im*2+$imc;
        $re=$re2-$im2+$rec;
        $re2=$re*$re;
        $im2=$im*$im;
        $color=$color-1;
      }
      if ( $color==0 ) {
        print &quot;_&quot;;
      } else {
        print &quot;#&quot;;
      }
    }
    print &quot;&lt;br&gt;&quot;;
    flush();
  }
}

/****/

function mandel2() {
  $b = &quot; .:,;!/&gt;)|&amp;IH%*#&quot;;
  //float r, i, z, Z, t, c, C;
  for ($y=30; printf(&quot;\n&quot;), $C = $y*0.1 - 1.5, $y--;){
    for ($x=0; $c = $x*0.04 - 2, $z=0, $Z=0, $x++ &lt; 75;){
      for ($r=$c, $i=$C, $k=0; $t = $z*$z - $Z*$Z + $r, $Z = 2*$z*$Z + $i, $z=$t, $k&lt;5000; $k++)
        if ($z*$z + $Z*$Z &gt; 500000) break;
      echo $b[$k%16];
    }
  }
}

/****/

function Ack($m, $n){
  if($m == 0) return $n+1;
  if($n == 0) return Ack($m-1, 1);
  return Ack($m - 1, Ack($m, ($n - 1)));
}

function ackermann($n) {
  $r = Ack(3,$n);
  print &quot;Ack(3,$n): $r\n&quot;;
}

/****/

function ary($n) {
  for ($i=0; $i&lt;$n; $i++) {
    $X[$i] = $i;
  }
  for ($i=$n-1; $i&gt;=0; $i--) {
    $Y[$i] = $X[$i];
  }
  $last = $n-1;
  print &quot;$Y[$last]\n&quot;;
}

/****/

function ary2($n) {
  for ($i=0; $i&lt;$n;) {
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;

    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
    $X[$i] = $i; ++$i;
  }
  for ($i=$n-1; $i&gt;=0;) {
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;

    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
    $Y[$i] = $X[$i]; --$i;
  }
  $last = $n-1;
  print &quot;$Y[$last]\n&quot;;
}

/****/

function ary3($n) {
  for ($i=0; $i&lt;$n; $i++) {
    $X[$i] = $i + 1;
    $Y[$i] = 0;
  }
  for ($k=0; $k&lt;1000; $k++) {
    for ($i=$n-1; $i&gt;=0; $i--) {
      $Y[$i] += $X[$i];
    }
  }
  $last = $n-1;
  print &quot;$Y[0] $Y[$last]\n&quot;;
}

/****/

function fibo_r($n){
    return(($n &lt; 2) ? 1 : fibo_r($n - 2) + fibo_r($n - 1));
}

function fibo($n) {
  $r = fibo_r($n);
  print &quot;$r\n&quot;;
}

/****/

function hash1($n) {
  for ($i = 1; $i &lt;= $n; $i++) {
    $X[dechex($i)] = $i;
  }
  $c = 0;
  for ($i = $n; $i &gt; 0; $i--) {
    if ($X[dechex($i)]) { $c++; }
  }
  print &quot;$c\n&quot;;
}

/****/

function hash2($n) {
  for ($i = 0; $i &lt; $n; $i++) {
    $hash1[&quot;foo_$i&quot;] = $i;
    $hash2[&quot;foo_$i&quot;] = 0;
  }
  for ($i = $n; $i &gt; 0; $i--) {
    foreach($hash1 as $key =&gt; $value) $hash2[$key] += $value;
  }
  $first = &quot;foo_0&quot;;
  $last  = &quot;foo_&quot;.($n-1);
  print &quot;$hash1[$first] $hash1[$last] $hash2[$first] $hash2[$last]\n&quot;;
}

/****/

function gen_random ($n) {
    global $LAST;
    return( ($n * ($LAST = ($LAST * IA + IC) % IM)) / IM );
}

function heapsort_r($n, &amp;$ra) {
    $l = ($n &gt;&gt; 1) + 1;
    $ir = $n;

    while (1) {
        if ($l &gt; 1) {
            $rra = $ra[--$l];
        } else {
            $rra = $ra[$ir];
            $ra[$ir] = $ra[1];
            if (--$ir == 1) {
                $ra[1] = $rra;
                return;
            }
        }
        $i = $l;
        $j = $l &lt;&lt; 1;
        while ($j &lt;= $ir) {
            if (($j &lt; $ir) &amp;&amp; ($ra[$j] &lt; $ra[$j+1])) {
                $j++;
            }
            if ($rra &lt; $ra[$j]) {
                $ra[$i] = $ra[$j];
                $j += ($i = $j);
            } else {
                $j = $ir + 1;
            }
        }
        $ra[$i] = $rra;
    }
}

function heapsort($N) {
  global $LAST;

  define(&quot;IM&quot;, 139968);
  define(&quot;IA&quot;, 3877);
  define(&quot;IC&quot;, 29573);

  $LAST = 42;
  for ($i=1; $i&lt;=$N; $i++) {
    $ary[$i] = gen_random(1);
  }
  heapsort_r($N, $ary);
  printf(&quot;%.10f\n&quot;, $ary[$N]);
}

/****/

function mkmatrix ($rows, $cols) {
    $count = 1;
    $mx = array();
    for ($i=0; $i&lt;$rows; $i++) {
        for ($j=0; $j&lt;$cols; $j++) {
            $mx[$i][$j] = $count++;
        }
    }
    return($mx);
}

function mmult ($rows, $cols, $m1, $m2) {
    $m3 = array();
    for ($i=0; $i&lt;$rows; $i++) {
        for ($j=0; $j&lt;$cols; $j++) {
            $x = 0;
            for ($k=0; $k&lt;$cols; $k++) {
                $x += $m1[$i][$k] * $m2[$k][$j];
            }
            $m3[$i][$j] = $x;
        }
    }
    return($m3);
}

function matrix($n) {
  $SIZE = 30;
  $m1 = mkmatrix($SIZE, $SIZE);
  $m2 = mkmatrix($SIZE, $SIZE);
  while ($n--) {
    $mm = mmult($SIZE, $SIZE, $m1, $m2);
  }
  print &quot;{$mm[0][0]} {$mm[2][3]} {$mm[3][2]} {$mm[4][4]}\n&quot;;
}

/****/

function nestedloop($n) {
  $x = 0;
  for ($a=0; $a&lt;$n; $a++)
    for ($b=0; $b&lt;$n; $b++)
      for ($c=0; $c&lt;$n; $c++)
        for ($d=0; $d&lt;$n; $d++)
          for ($e=0; $e&lt;$n; $e++)
            for ($f=0; $f&lt;$n; $f++)
             $x++;
  print &quot;$x\n&quot;;
}

/****/

function sieve($n) {
  $count = 0;
  while ($n-- &gt; 0) {
    $count = 0;
    $flags = range (0,8192);
    for ($i=2; $i&lt;8193; $i++) {
      if ($flags[$i] &gt; 0) {
        for ($k=$i+$i; $k &lt;= 8192; $k+=$i) {
          $flags[$k] = 0;
        }
        $count++;
      }
    }
  }
  print &quot;Count: $count\n&quot;;
}

/****/

function strcat($n) {
  $str = &quot;&quot;;
  while ($n-- &gt; 0) {
    $str .= &quot;hello\n&quot;;
  }
  $len = strlen($str);
  print &quot;$len\n&quot;;
}

/*****/

function getmicrotime()
{
  $t = gettimeofday();
  return ($t['sec'] + $t['usec'] / 1000000);
}

function start_test()
{
        ob_start();
  return getmicrotime();
}

function end_test($start, $name)
{
  global $total;
  $end = getmicrotime();
  ob_end_clean();
  $total += $end-$start;
  $num = number_format($end-$start,3);
  $pad = str_repeat(&quot; &quot;, 24-strlen($name)-strlen($num));

  echo $name.$pad.$num.&quot;\n&quot;;
        ob_start();
  return getmicrotime();
}

function total()
{
  global $total;
  $pad = str_repeat(&quot;-&quot;, 24);
  echo $pad.&quot;\n&quot;;
  $num = number_format($total,3);
  $pad = str_repeat(&quot; &quot;, 24-strlen(&quot;Total&quot;)-strlen($num));
  echo &quot;Total&quot;.$pad.$num.&quot;\n&quot;;
}

$t0 = $t = start_test();
simple();
$t = end_test($t, &quot;simple&quot;);
simplecall();
$t = end_test($t, &quot;simplecall&quot;);
simpleucall();
$t = end_test($t, &quot;simpleucall&quot;);
simpleudcall();
$t = end_test($t, &quot;simpleudcall&quot;);
mandel();
$t = end_test($t, &quot;mandel&quot;);
mandel2();
$t = end_test($t, &quot;mandel2&quot;);
ackermann(7);
$t = end_test($t, &quot;ackermann(7)&quot;);
ary(50000);
$t = end_test($t, &quot;ary(50000)&quot;);
ary2(50000);
$t = end_test($t, &quot;ary2(50000)&quot;);
ary3(2000);
$t = end_test($t, &quot;ary3(2000)&quot;);
fibo(30);
$t = end_test($t, &quot;fibo(30)&quot;);
hash1(50000);
$t = end_test($t, &quot;hash1(50000)&quot;);
hash2(500);
$t = end_test($t, &quot;hash2(500)&quot;);
heapsort(20000);
$t = end_test($t, &quot;heapsort(20000)&quot;);
matrix(20);
$t = end_test($t, &quot;matrix(20)&quot;);
nestedloop(12);
$t = end_test($t, &quot;nestedloop(12)&quot;);
sieve(30);
$t = end_test($t, &quot;sieve(30)&quot;);
strcat(200000);
$t = end_test($t, &quot;strcat(200000)&quot;);
total($t0, &quot;Total&quot;);
?&gt;
</pre>
</p>
<p><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_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_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_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/2009/10/15/1131.html#comment-2266" >2009/10/15</a>, <a href="http://www.codytan.com"  rel="external nofollow"  class="url" >cody</a> writes: 好文，不过有些疑问
1.“对于每个Opcode都会分发执行”，这里的“个"指的是？是一条opcode语句还是一个php文件中所有的opcode语句？
2.有个问题，php的错误检查阶段是哪个？不是语法检查。如include一个不存在的问题，php会报错，这个报错是在opcode-&gt;compile-&gt;执行中的哪个环节报错的？是compile环节还是执行环节呢？
3.其实问题二是基于对php运行机制还不太清楚，我测试过一个文件 include 20个php文件和直接写成一个php文件性能上的差异很大（20文件并不执行），想知道是在哪个环境造成了这种差异。

如果能回答我，感激不尽！ :)</li><li><a href="http://www.laruence.com/2009/10/15/1131.html#comment-2267" >2009/10/15</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @cody 应该是对于每条opline中的opcode. 都会通过分发对应到相应的处理器执行(zend_vm_def.h定义).
include也是一条opcode,ZEND_INCLUDE_OR_EVAL, 相应的出错检查也就是在它的处理器中.</li><li><a href="http://www.laruence.com/2009/10/15/1131.html#comment-2268" >2009/10/15</a>, <a href="http://www.codytan.com"  rel="external nofollow"  class="url" >cody</a> writes: 补充一下，”opcode-&gt;compile-&gt;执行“ 我这里的compile指的其实是由opcode到c 这个过程。</li><li><a href="http://www.laruence.com/2009/10/15/1131.html#comment-2269" >2009/10/15</a>, cody writes: thanks</li><li><a href="http://www.laruence.com/2009/10/15/1131.html#comment-2272" >2009/10/17</a>, fybird writes: 请问你是用那个ide编程，平常。</li><li><a href="http://www.laruence.com/2009/10/15/1131.html#comment-2273" >2009/10/17</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @fybird vim</li><li><a href="http://www.laruence.com/2009/10/15/1131.html#comment-2285" >2009/10/24</a>, <a href="http://www.05sky.cn"  rel="external nofollow"  class="url" >CrossYou</a> writes: 我也使用了你同样的主题，呵呵

你的文章写的很深，我才刚刚接触php，学习中，楼主加油。</li><li><a href="http://www.laruence.com/2009/10/15/1131.html#comment-2290" >2009/10/26</a>, zhangyufeng writes: http://twiki.laruence.com/ 打不开啦……</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/10/15/1131.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>关于Javascript的俩个有趣的探讨</title>
		<link>http://www.laruence.com/2009/09/27/1123.html</link>
		<comments>http://www.laruence.com/2009/09/27/1123.html#comments</comments>
		<pubDate>Sun, 27 Sep 2009 10:54:44 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[Js/CSS]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[事件处理]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[正则]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1123</guid>
		<description><![CDATA[1. 关于事件处理函数引用的一个佐证

2. Javascript正则的效率问题]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/09/27/1123.html"  title="Permanet Link to 关于Javascript的俩个有趣的探讨" >http://www.laruence.com/2009/09/27/1123.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
  <b> 首先祝贺在经历了几乎一天的等待以后. 我的空间商终于把服务器迁到了电信机房, 外加网通CDN加速. </b></p>
<h3>关于事件处理函数引用的一个佐证</h3>
<p>   之前, 我在分析Javascript的This关键字的时候, 说过, 当使用inline的方式写dom元素的事件处理函数的时候, 采用的是引用的方式. 刚好nullbyte童鞋给我提供了一个很有意思的Case:</p>
<pre name="code"  class="sh_javascript"  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;img id=&quot;foo&quot; src=&quot;xxx&quot; onerror=&quot; alert('error');
    } function foobar() {
          alert('www.laruence.com'); &quot; /&gt;
&lt;script&gt;
alert(document.getElementById(&quot;foo&quot;).onerror);
&lt;/script&gt;
</pre>
<p>    在IE下试试看..</p>
<p>    不过, FF和Chrome下都不行, 应该是FF和Chrome都会验证html代码的合法性.
</p>
<p><h3>Javascript正则的效率</h3>
<p>   如果你看到有人写Javascript的trim的时候采用了循环的方式,而不是正则的方式, 请不要笑. 人家这可是经验所致, 考虑如下代码的执行时间会是多少?</p>
<pre name="code"  class="sh_javascript"  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;">
var matchs = /^(a+)+$/.exec(&quot;aaaaaaaaaaaaaaaaaaaaaaaaaaaX&quot;);
alert(matchs);
</pre>
<p>   告诉你吧&#8230;. 注:以下结果来自看手表估测, 但不影响时间的长度性&#8230;另外jsmore的stauren同学也验证了这一结论:</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;">
IE8: 30秒
FF3: 28秒
号称目前最快的采用V8引擎的Chrome: 8秒.
</pre>
<p>   这个结果,,,是多么的不可接受啊? 具体原因的分析, 在master regular expression里面有提到过.</p>
<blockquote><p>
NFA和DFA的引擎是有区别的。js/perl/php/java/.net都是NFA引擎。<br/>
而DFA与NFA机制上的不同带来5个影响：<br/>
1. DFA对于文本串里的每一个字符只需扫描一次，比较快，但特性较少；NFA要翻来覆去吃字符、吐字符，速度慢，但是特性丰富，所以反而应用广泛，当今主要的正则表达式引擎，如Perl、Ruby、Python的re模块、Java和.NET的regex库，都是NFA的。<br/>
2. 只有NFA才支持lazy和backreference（后向引用）等特性；<br/>
3. NFA急于邀功请赏，所以最左子正则式优先匹配成功，因此偶尔会错过最佳匹配结果；DFA则是“最长的左子正则式优先匹配成功”。<br/>
4. NFA缺省采用greedy量词(就是对于/.*/、/\w+/这样的“重复n”次的模式，以贪婪方式进行，尽可能匹配更多字符，直到不得以罢手为止)，NFA会优先匹配量词。<br/>
5. NFA可能会陷入递归调用的陷阱而表现得性能极差。</p>
<p>backtracking（回朔）<br/>
当NFA发现自己吃多了，一个一个往回吐，边吐边找匹配，这个过程叫做backtracking。由于存在这个过程，在NFA匹配过程中，特别是在编写不合理的正则式匹配过程中，文本被反复扫描，效率损失是不小的。明白这个道理，对于写出高效的正则表达式很有帮助。
</p></blockquote>
<p>而对于Javascript中的正则来说, 应该是优先匹配量词, 导致了很深的递归, 形成了性能问题&#8230;
</p>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_javascript.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_javascript.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/2009/09/27/1123.html#comment-2243" >2009/09/27</a>, <a href="http://www.phpfans.org"  rel="external nofollow"  class="url" >深空</a> writes: 没看明白要匹配什么？应该也是尽可能多的匹配a，但是因为最后一个是X，所以打印出null，厄，直接写a+不就行了，在PHP里很快，呵呵。</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2244" >2009/09/28</a>, cjj writes: 呵呵 好的正则 才能让正则有好的性能</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2245" >2009/09/28</a>, yuehei writes: 测试了一下，果然很慢。。以后少用正则，
可是为什么测试的正则要有两个+号呢
 /^(a+)$/.exec("aaaaaaaaaaaaaaaaaaaaaaaaaaaX");

一个加号倒是很快。。</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2246" >2009/09/28</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @cjj 有理, 正则也是一门独立的艺术.</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2250" >2009/10/01</a>, <a href="www.phppan.com"  rel="external nofollow"  class="url" >phppan</a> writes: 首先，恭喜
然后，国庆快乐
最后，虽然把精通正则表达式看过了，但是对此的了解依然不够。学习了</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2260" >2009/10/12</a>, toms writes: 求求大侠能不能帮我看个js问题啊，问题如下

有两个页面a, b 其中a为表单页面b为数据接收页面

a中的数据表单使用onsubmit事件验证客户端数据有效性， 但如果我在服务器（页面b）上检测到提交上来的数据不符合要求， 我使用history.go(-1), 返回前一个页面后， 在页面a数据表单无法提交（没有报任何js错误）， 在表单内回车和点“submit”均无法提交表单， 经检查发现在b页面history.go(-1)回到a页面后， onsubmit事件无法响应， 此问题仅在firefox下出现， 并且firebug和错误控制台均未报出任何js错误，第一次提交的时候所有js都正常运行了的</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2261" >2009/10/12</a>, toms writes: b页面history.go(-1)后， a页面onsubmit事件里的任何东西都无法执行， 排除了验证函数错误</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2262" >2009/10/13</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @toms sorry, 我没有重现出来, 你能把你的代码mail到我的yahoo邮箱么?</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2270" >2009/10/16</a>, <a href="http://www.xidea.org"  rel="external nofollow"  class="url" >jindw</a> writes: 够诡异，够专业。</li><li><a href="http://www.laruence.com/2009/09/27/1123.html#comment-2292" >2009/10/26</a>, <a href="http://www.pigblog.net"  rel="external nofollow"  class="url" >Cherry</a> writes: 你的JS也是如此的牛啊</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/09/27/1123.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>PHP文件上传源码分析(RFC1867)</title>
		<link>http://www.laruence.com/2009/09/26/1103.html</link>
		<comments>http://www.laruence.com/2009/09/26/1103.html#comments</comments>
		<pubDate>Sat, 26 Sep 2009 04:27:04 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php源码分析]]></category>
		<category><![CDATA[rfc1867]]></category>
		<category><![CDATA[文件上传]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1103</guid>
		<description><![CDATA[文件上传,一般分为俩种方式FTP和HTTP, 对于我们的互联网应用来说: FTP上传虽然传输稳定, 但是易用性和安全性都是个问题.  你总不至于在用户要上传头像的时候告诉用户"请打开FTP客户端,上传文件到http://www.laruence.com/uploads/中, 并以2dk433423l.jpg命名"吧? 

而基于HTTP的上传,相对来说易用性和安全性上就比FTP要增强了很多. 可以应用的上传方式有PUT, WEBDAV, 和RFC1867三种, 本文将分析在PHP中,是如何基于RFC1867实现文件上传的.]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/09/26/1103.html"  title="Permanet Link to PHP文件上传源码分析(RFC1867)" >http://www.laruence.com/2009/09/26/1103.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
文件上传,一般分为俩种方式FTP和HTTP, 对于我们的互联网应用来说: FTP上传虽然传输稳定, 但是易用性和安全性都是个问题.  你总不至于在用户要上传头像的时候告诉用户&#8221;请打开FTP客户端,上传文件到http://www.laruence.com/uploads/中, 并以2dk433423l.jpg命名&#8221;吧? </p>
<p>而基于HTTP的上传,相对来说易用性和安全性上就比FTP要增强了很多. 可以应用的上传方式有PUT, WEBDAV, 和RFC1867三种, 本文将分析在PHP中,是如何基于RFC1867实现文件上传的.
</p>
<h3>RFC1867</h3>
<p>
RCF1867是Form-based File Upload in HTML标准协议, RFC1867标准对HTML做出了两处修改：<br/>
　</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;">
1 为input元素的type属性增加了一个file选项。
2 input标记可以具有accept属性，该属性能够指定可被上传的文件类型或文件格式列表。
</pre>
<p>　　<br/>
	另外，本标准还定义了一种新的mime类型：multipart/form-data，以及当处理一个带有enctype=&#8221;multipart/form-data&#8221; 并且/或含有&lt;input type=&#8221;file&#8221;&gt;的标记的表单时所应该采取的行为。<br/>
　　<br/>
	举例来说，当HTML想让用户能够上传一个或更多的文件时，他可以这么写：</p>
<pre name="code"  class="sh_html"  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;form enctype=&quot;multipart/form-data&quot; action=&quot;upload.php&quot; method=post&gt;
选择文件:
&lt;input name=&quot;userfile&quot; type=&quot;file&quot;&gt;
文件描述:
&lt;input name=&quot;description&quot; type=&quot;text&quot;&gt;
&lt;input type=&quot;submit&quot; value=&quot;上传&quot;&gt;
&lt;/form&gt;
</pre>
<p>	这个表单, 大家一定不陌生, 而对于PHP来说, 它自己另外定义了一个默认表单元素MAX_FILE_SIZE, 用户可以通过这个隐藏的表单元素来建议PHP最多只容许上传文件的大小, 比如对于上面的例子, 我们希望用户上传的文件不能大于5000(5k)字节, 那么可以如下写:</p>
<pre name="code"  class="sh_html"  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;form enctype=&quot;multipart/form-data&quot; action=&quot;upload.php&quot; method=post&gt;
&lt;input type=&quot;hidden&quot; value=&quot;5000&quot; name=&quot;MAX_FILE_SIZE&quot;&gt; &lt;!--文件大小--&gt;
选择文件:
&lt;input name=&quot;userfile&quot; type=&quot;file&quot;&gt;
文件描述:
&lt;input name=&quot;description&quot; type=&quot;text&quot;&gt;
&lt;input type=&quot;submit&quot; value=&quot;上传&quot;&gt;
&lt;/form&gt;
</pre>
<p>	姑且不说, 这个MAX_FILE_SIZE是多么的不可靠(所以基于浏览器的控制,都是不可靠的), 我们单纯从实现来介绍这个MAX_FILE_SIZE是如何起作用的.</p>
<p>	当用户选择了一个文件(laruence.txt), 并填写好文件描述(&#8220;laruence的个人介绍&#8221;), 点击上传后, 发生了什么呢?</p>
<h3>表单提交</h3>
<p>	在用户确定提交以后, 浏览器会根据用户选择的输入, 读取要上传的文件, 连同表单中的其他元素, 组织成一定格式(如下)的数据发送到form中action属性指定的页面(在本例中是upload.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;">
//请求头
POST /upload.php HTTP/1.0\r\n
...
Host: www.laruence.com\r\n
...
Content-length: xxxxx\r\n
...
Content-type: multipart/form-data, boundary=--------------7d51863950254\r\n
...\r\n\r\n
//开始POST数据内容
---------------7d51863950254
content-disposition: form-data; name=&quot;description&quot;
laruence的个人介绍
---------------7d51863950254
content-disposition: form-data; name=&quot;userfile&quot;; filename=&quot;laruence.txt&quot;
Content-Type: text/plain
... laruence.txt 的内容...
---------------7d51863950254
</pre>
<p>	接下来, 就是服务器, 是如何处理这些数据了.</p>
<h3>接受上传</h3>
<p>
	当Web服务器, 此处假设为Apache(另外假设PHP是以module方式安装在Apache上的), 接受到用户的数据时, 首先它根据HTTP请求头, 通过确定MIME TYPE为PHP类型, 然后经过一些过程以后(这部分,可以参看我之前的<a href="http://www.laruence.com/2008/08/15/283.html"  target="_blank" >PHP Life Cycle ppt</a>), 最终会把控制权交给PHP模块.</p>
<p>	这个时候, PHP会调用sapi_activate来初始化一个请求, 在这个过程中, 首先判断请求类型, 此时是POST, 从而去调用sapi_read_post_data, 通过Content-type, 找到rfc1867的处理函数rfc1867_post_handler, 从而调用这个handler, 来分析POST来的数据.</p>
<p>	关于rfc1867_post_handler这部分的源代码, 可以在mian/rfc1867.c找到, 另外也可以参看我之前的<a href="http://www.laruence.com/2008/11/07/586.html"  target="_blank" >深入理解PHP之文件上传</a>, 其中也列出的源代码.</p>
<p>    然后, PHP通过boundary, 对于每一个分段, 都通过检查, 是否同时定义了:</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;">
	name和filename属性(有名文件上传)
	没有定义name定义了filename(无名上传)
	定义了name没有定义filename(普通数据),
</pre>
<p>	从而进行不同的处理.</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;">
if ((cd = php_mime_get_hdr_value(header, &quot;Content-Disposition&quot;))) {
	char *pair=NULL;
	int end=0;

	while (isspace(*cd)) {
		++cd;
	}

	while (*cd &amp;&amp; (pair = php_ap_getword(&amp;cd, ';')))
	{
		char *key=NULL, *word = pair;

		while (isspace(*cd)) {
			++cd;
		}

		if (strchr(pair, '=')) {
			key = php_ap_getword(&amp;pair, '=');

			if (!strcasecmp(key, &quot;name&quot;)) {
				//获取name字段
				if (param) {
					efree(param);
				}
				param = php_ap_getword_conf(&amp;pair TSRMLS_CC);
			} else if (!strcasecmp(key, &quot;filename&quot;)) {
				//获取filename字段
				if (filename) {
					efree(filename);
				}
				filename = php_ap_getword_conf(&amp;pair TSRMLS_CC);
			}
		}
		if (key) {
			efree(key);
		}
		efree(word);
	}
</pre>
<p>在这个过程中, PHP会去检查普通数据中,是否有MAX_FILE_SIZE.</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;">
 /* Normal form variable, safe to read all data into memory */
if (!filename &amp;&amp; param) {
	unsigned int value_len;
	char *value = multipart_buffer_read_body(mbuff, &amp;value_len TSRMLS_CC);
	unsigned int new_val_len; /* Dummy variable */
	......

	if (!strcasecmp(param, &quot;MAX_FILE_SIZE&quot;)) {
                  max_file_size = atol(value);
    }

	efree(param);
	efree(value);
	continue;
}
</pre>
<p>有的话, 就会按照它的值来检查文件大小是否超出.</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;">
if (PG(upload_max_filesize) &gt; 0 &amp;&amp; total_bytes &gt; PG(upload_max_filesize)) {
	cancel_upload = UPLOAD_ERROR_A;
} else if (max_file_size &amp;&amp; (total_bytes &gt; max_file_size)) {
#if DEBUG_FILE_UPLOAD
	sapi_module.sapi_error(E_NOTICE,
		&quot;MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved&quot;,
		 max_file_size, param, filename);
#endif
	cancel_upload = UPLOAD_ERROR_B;
}
</pre>
<p>通过上面的代码,我们也可以看到, 判断分为俩部, 第一部分是检查PHP默认的上传上限. 第二部分才是检查用户自定义的MAX_FILE_SIZE, 所以表单中定义的MAX_FILE_SIZE并不能超过PHP中设置的最大上传文件大小.</p>
<p>通过对name和filename的判断, 如果是文件上传, 会根据php的设置, 在文件上传目录中创建一个随机名字的临时文件:</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;">
 if (!skip_upload) {
	/* Handle file */
	fd = php_open_temporary_fd_ex(PG(upload_tmp_dir),
			 &quot;php&quot;, &amp;temp_filename, 1 TSRMLS_CC);
	if (fd==-1) {
		sapi_module.sapi_error(E_WARNING,
			 &quot;File upload error - unable to create a temporary file&quot;);
		cancel_upload = UPLOAD_ERROR_E;
	}
}
</pre>
<p>返回文件句柄, 和临时随机文件名.</p>
<p>之后, 还会有一些验证,比如文件名合法, name合法等.</p>
<p>如果这些验证都通过, 那么就把内容读入, 写入到这个临时文件中.</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;">
.....
else if (blen &gt; 0) {
	wlen = write(fd, buff, blen); //写入临时文件.
	if (wlen == -1) {
	/* write failed */
#if DEBUG_FILE_UPLOAD
	sapi_module.sapi_error(E_NOTICE, &quot;write() failed - %s&quot;, strerror(errno));
#endif
	cancel_upload = UPLOAD_ERROR_F;
	}
}
....
</pre>
<p>当循环读入完成后, 关闭临时文件句柄. 记录临时变量名: </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;">
zend_hash_add(SG(rfc1867_uploaded_files), temp_filename,
	strlen(temp_filename) + 1, &amp;temp_filename, sizeof(char *), NULL);
</pre>
<p>并且生成FILE变量, 这个时候, 如果是有名上传, 那么就会设置:</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;">
$_FILES['userfile'] //name=&quot;userfile&quot;
</pre>
<p>如果是无名上传, 则会使用tmp_name来设置:</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;">
$_FILES['tmp_name'] //无名上传
</pre>
<p>最终交给用户编写的upload.php处理.</p>
<p>这时在upload.php中, 用户就可以通过move_uploaded_file来操作刚才生成的文件了~
</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_html.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_html.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_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_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_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></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/09/26/1103.html#comment-2235" >2009/09/26</a>, <a href="http://phpzxh.cnblogs.com/"  rel="external nofollow"  class="url" >phpzxh</a> writes: 你的文章都是讲的很深入的，我要把php的源码下载下来看了。</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2236" >2009/09/26</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 最近越来越觉得,我的文字表达能力差了....sigh, 大家将就的看,看不懂的,尽管问...</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2240" >2009/09/26</a>, <a href="http://unixhater.com"  rel="external nofollow"  class="url" >unixhater.com</a> writes: 我是php菜鸟,PHP默认的上传上限怎么查看与设置？filename是文件名，那name是怎么指定的，比如你传了文件laruence.txt，name是什么？

另你用的语法高亮插件是哪种？</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2241" >2009/09/26</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: name是input的name.

我使用的不是插件, 是shjs的css+js</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2242" >2009/09/26</a>, fybird writes: 第一次看，没看懂。继续看……</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2247" >2009/09/28</a>, sychen writes: 好文章，收藏了...</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2251" >2009/10/01</a>, <a href="www.phppan.com"  rel="external nofollow"  class="url" >phppan</a> writes: 风雪，在生成临时文件时，文件的名字有没有规律？或者说是随机？</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2258" >2009/10/10</a>, <a href="http://men-zone.net"  rel="external nofollow"  class="url" >刘永赞</a> writes: 你好，拜读了你的文章,受益匪浅

希望能和你做朋友

我也正在开始研究php源码

热切盼望您的邮件</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2306" >2009/11/10</a>, <a href="http://www.fishingsnow.com"  rel="external nofollow"  class="url" >钓雪</a> writes: 感谢楼主的分享，受益匪浅！</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2335" >2009/11/26</a>, 帅得惊动了党 writes: 哥们，你有空分析一下file_get_contents这个函数底层是怎么实现的吧．．．
以下是函数跟踪过程：
PHP_FUNCTION(file_get_contents)
php_stream_open_wrapper_ex
_php_stream_open_wrapper_ex
wrapper = php_stream_locate_url_wrapper
wrapper-&gt;wops-&gt;stream_opener
typedef struct _php_stream_wrapper_ops php_stream_wrapper_ops
php_plain_files_wrapper_ops
php_plain_files_stream_opener
php_stream_fopen_with_path_rel
_php_stream_fopen_with_path
php_stream_fopen_rel
_php_stream_fopen 
到了后来就整不明白了，php里面用了一个叫做的流的东西，一切与文件，网络有关的东西都是用流实现的，流是个很好很强大的东西．不知道你能不能把这一块分析透，期待ing!</li><li><a href="http://www.laruence.com/2009/09/26/1103.html#comment-2416" >2010/01/04</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/09/26/1103.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>深入理解JavaScript定时机制</title>
		<link>http://www.laruence.com/2009/09/23/1089.html</link>
		<comments>http://www.laruence.com/2009/09/23/1089.html#comments</comments>
		<pubDate>Wed, 23 Sep 2009 07:18:28 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[Js/CSS]]></category>
		<category><![CDATA[转载]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[单线程]]></category>
		<category><![CDATA[原理]]></category>
		<category><![CDATA[定时器]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1089</guid>
		<description><![CDATA[<pre class="sh_javascript">
setTimeout(function() {
    alert('你好!');
}, 0);
setInterval(callbackFunction, 100);
</pre>

认为setTimeout中的问候方法会立即被执行,因为这并不是凭空而说,而是JavaScript API文档明确定义第二个参数意义为隔多少毫秒后,回调方法就会被执行. 这里设成0毫秒,理所当然就立即被执行了.
同理对setInterval的callbackFunction方法每间隔100毫秒就立即被执行深信不疑!

但随着JavaScript应用开发经验不断的增加和丰富,有一天你发现了一段怪异的代码而百思不得其解.....]]></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/2009/09/23/1089.html"  title="Permanet Link to 深入理解JavaScript定时机制" >http://www.laruence.com/2009/09/23/1089.html</a></li>
<li>转载文章</li>
</ul></div>
<p>转帖地址:<a href="http://www.9demo.com/archives/341" >http://www.9demo.com/archives/341</a></p>
<p>容易欺骗别人感情的JavaScript定时器</p>
<p>JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如</p>
<pre class="sh_javascript"   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;">
setTimeout(function() {
    alert('你好!');
}, 0);
setInterval(callbackFunction, 100);
</pre>
<p>认为setTimeout中的问候方法会立即被执行,因为这并不是凭空而说,而是JavaScript API文档明确定义第二个参数意义为隔多少毫秒后,回调方法就会被执行. 这里设成0毫秒,理所当然就立即被执行了.<br/>
同理对setInterval的callbackFunction方法每间隔100毫秒就立即被执行深信不疑!</p>
<p>但随着JavaScript应用开发经验不断的增加和丰富,有一天你发现了一段怪异的代码而百思不得其解:</p>
<pre class="sh_javascript"   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;">
div.onclick = function(){
        setTimeout(function() {
                document.getElementById('inputField').focus();
        }, 0);
};
</pre>
<p>既然是0毫秒后执行,那么还用setTimeout干什么, 此刻, 坚定的信念已开始动摇.</p>
<p>直到最后某一天 , 你不小心写了一段糟糕的代码:</p>
<pre class="sh_javascript"   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;">
setTimeout(function() {
        while (true) {
        }
}, 100);
setTimeout(function() {
        alert('你好!');
}, 200);
setInterval(callbackFunction, 200);
</pre>
<p>第一行代码进入了死循环,但不久你就会发现,第二,第三行并不是预料中的事情,alert问候未见出现,callbacKFunction也杳无音讯!</p>
<p>这时你彻底迷惘了,这种情景是难以接受的,因为改变长久以来既定的认知去接受新思想的过程是痛苦的,但情事实摆在眼前,对JavaScript真理的探求并不会因为痛苦而停止,下面让我们来展开JavaScript线程和定时器探索之旅!</p>
<p>拔开云雾见月明</p>
<p>出现上面所有误区的最主要一个原因是:潜意识中认为,JavaScript引擎有多个线程在执行,JavaScript的定时器回调函数是异步执行的.</p>
<p>而事实上的,JavaScript使用了障眼法,在多数时候骗过了我们的眼睛,这里背光得澄清一个事实:</p>
<p>JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序.</p>
<p>JavaScript引擎用单线程运行也是有意义的,单线程不必理会线程同步这些复杂的问题,问题得到简化.</p>
<p>那么单线程的JavaScript引擎是怎么配合浏览器内核处理这些定时器和响应浏览器事件的呢?<br/>
下面结合浏览器内核处理方式简单说明.</p>
<p>浏览器内核实现允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步.假如某一浏览器内核的实现至少有三个常驻线程:javascript引擎线程,界面渲染线程,浏览器事件触发线程,除些以外,也有一些执行完就终止的线程,如Http请求线程,这些异步线程都会产生不同的异步事件,下面通过一个图来阐明单线程的JavaScript引擎与另外那些线程是怎样互动通信的.虽然每个浏览器内核实现细节不同,但这其中的调用原理都是大同小异.</p>
<div id="attachment_1090"  class="wp-caption aligncenter"  style="width: 510px" ><a href="http://www.laruence.com/wp-content/uploads/jstimer.jpg" ><img src="http://www.laruence.com/wp-content/uploads/jstimer.jpg"  alt="Js线程图示"  title="jstimer"  width="500"  height="272"  class="size-full wp-image-1090" /></a><p class="wp-caption-text" >Js线程图示</p></div>
<p>由图可看出,浏览器中的JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,这些任务可以源自JavaScript引擎当前执行的代码块,如调用setTimeout添加一个任务,也可来自浏览器内核的其它线程,如界面元素鼠标点击事件,定时触发器时间到达通知,异步请求状态变更通知等.从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线程关系,这些任务得进行排队,一个接着一个被引擎处理.</p>
<p>上图t1-t2..tn表示不同的时间点,tn下面对应的小方块代表该时间点的任务,假设现在是t1时刻,引擎运行在t1对应的任务方块代码内,在这个时间点内,我们来描述一下浏览器内核其它线程的状态.</p>
<p>t1时刻:</p>
<p>GUI渲染线程:</p>
<p>该线程负责渲染浏览器界面HTML元素,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行.本文虽然重点解释JavaScript定时机制,但这时有必要说说渲染线程,因为该线程与JavaScript引擎线程是互斥的,这容易理解,因为JavaScript脚本是可操纵DOM元素,在修改这些元素属性同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致了.</p>
<p>在JavaScript引擎运行脚本期间,浏览器渲染线程都是处于挂起状态的,也就是说被”冻结”了.</p>
<p>所以,在脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出来,这些操作将保存在一个队列中,待JavaScript引擎空闲时才有机会渲染出来.</p>
<p>GUI事件触发线程:</p>
<p>JavaScript脚本的执行不影响html元素事件的触发,在t1时间段内,首先是用户点击了一个鼠标键,点击被浏览器事件触发线程捕捉后形成一个鼠标点击事件,由图可知,对于JavaScript引擎线程来说,这事件是由其它线程异步传到任务队列尾的,由于引擎正在处理t1时的任务,这个鼠标点击事件正在等待处理.</p>
<p>定时触发线程:</p>
<p>注意这里的浏览器模型定时计数器并不是由JavaScript引擎计数的,因为JavaScript引擎是单线程的,如果处于阻塞线程状态就计不了时,它必须依赖外部来计时并触发定时,所以队列中的定时事件也是异步事件.</p>
<p>由图可知,在这t1的时间段内,继鼠标点击事件触发后,先前已设置的setTimeout定时也到达了,此刻对JavaScript引擎来说,定时触发线程产生了一个异步定时事件并放到任务队列中, 该事件被排到点击事件回调之后,等待处理.<br/>
同理, 还是在t1时间段内,接下来某个setInterval定时器也被添加了,由于是间隔定时,在t1段内连续被触发了两次,这两个事件被排到队尾等待处理.</p>
<p>可见,假如时间段t1非常长,远大于setInterval的定时间隔,那么定时触发线程就会源源不断的产生异步定时事件并放到任务队列尾而不管它们是否已被处理,但一旦t1和最先的定时事件前面的任务已处理完,这些排列中的定时事件就依次不间断的被执行,这是因为,对于JavaScript引擎来说,在处理队列中的各任务处理方式都是一样的,只是处理的次序不同而已.</p>
<p>t1过后,也就是说当前处理的任务已返回,JavaScript引擎会检查任务队列,发现当前队列非空,就取出t2下面对应的任务执行,其它时间依此类推,由此看来:</p>
<p>如果队列非空,引擎就从队列头取出一个任务,直到该任务处理完,即返回后引擎接着运行下一个任务,在任务没返回前队列中的其它任务是没法被执行的.</p>
<p>相信您现在已经很清楚JavaScript是否可多线程,也了解理解JavaScript定时器运行机制了,下面我们来对一些案例进行分析:</p>
<p>案例1:setTimeout与setInterval</p>
<pre class="sh_javascript"   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;">
setTimeout(function() {
        /* 代码块... */
        setTimeout(arguments.callee, 10);
}, 10);

setInterval(function(){
        /*代码块... */
}, 10);
</pre>
<p>这两段代码看一起效果一样,其实非也,第一段中回调函数内的setTimeout是JavaScript引擎执行后再设置新的setTimeout定时, 假定上一个回调处理完到下一个回调开始处理为一个时间间隔,理论两个setTimeout回调执行时间间隔>=10ms .第二段自setInterval设置定时后,定时触发线程就会源源不断的每隔十秒产生异步定时事件并放到任务队列尾,理论上两个setInterval回调执行时间间隔<=10.</p>
<p>案例2:ajax异步请求是否真的异步?</p>
<p>很多同学朋友搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?<br/>
其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求(参见上图),当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行onreadystatechange所设置的函数.<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_javascript.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_javascript.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_javascript.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_javascript.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/09/23/1089.html#comment-2232" >2009/09/23</a>, <a href="http://hqlong.com"  rel="external nofollow"  class="url" >hqlong</a> writes: 分析问题很有深度，似乎是你的风格。</li><li><a href="http://www.laruence.com/2009/09/23/1089.html#comment-2233" >2009/09/24</a>, silasoni writes: 博主分析问题很有深度是没错
不过这篇是转贴的呀</li><li><a href="http://www.laruence.com/2009/09/23/1089.html#comment-2248" >2009/09/29</a>, aaaaaa writes: 很多是转载的，不过博主整理知识还是很认真的</li><li><a href="http://www.laruence.com/2009/09/23/1089.html#comment-2249" >2009/09/29</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</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>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/09/23/1089.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
