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

<channel>
	<title>风雪之隅 &#187; PHP</title>
	<atom:link href="http://www.laruence.com/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.laruence.com</link>
	<description>PHP应用,PHP源码分析,Zend引擎分析,Web相关技术研究,Web技术分享 - 左手代码 右手诗</description>
	<lastBuildDate>Sat, 04 Sep 2010 15:10:16 +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>Yaf-一个PHP扩展实现的PHP框架</title>
		<link>http://www.laruence.com/2010/09/04/1736.html</link>
		<comments>http://www.laruence.com/2010/09/04/1736.html#comments</comments>
		<pubDate>Sat, 04 Sep 2010 04:22:37 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[随笔]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHP extension]]></category>
		<category><![CDATA[PHP扩展]]></category>
		<category><![CDATA[PHP框架]]></category>
		<category><![CDATA[Yaf]]></category>
		<category><![CDATA[yet another framework]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1736</guid>
		<description><![CDATA[快有一个月没有更新Blog了, 一来是最近项目比较紧张, 二来就是在忙着开发<a href="http://www.laruence.com/yaf/manual/" target="_blank">Yaf(Yet another Framework)</a>

    一直以来, 我研究PHP的内核, 虽然有文章不少, 但却鲜有一些借助这些研究成果而来的, 实际的东西, 也就无法让更多人学习到对Zend API的实际运用.

    我思考了一段时间, 觉得有必要写一个扩展出来, 这个扩展要用到很多Zend API, 要用到很多在网上的PHP扩展开发中,鲜有叙及的部分(比如, 实现类/接口, 继承, 自动加载,等等), 让更多的PHP扩展开发者可以借鉴.]]></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/09/04/1736.html"  title="Permanet Link to Yaf-一个PHP扩展实现的PHP框架" >http://www.laruence.com/2010/09/04/1736.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
    快有一个月没有更新Blog了, 一来是最近项目比较紧张, 二来就是在忙着开发<a href="http://www.laruence.com/yaf/manual/"  target="_blank" >Yaf(Yet another Framework)</a></p>
<p>    一直以来, 我研究PHP的内核, 虽然有文章不少, 但却鲜有一些借助这些研究成果而来的, 实际的东西, 也就无法让更多人学习到对Zend API的实际运用.</p>
<p>    我思考了一段时间, 觉得有必要写一个扩展出来, 这个扩展要用到很多Zend API, 要用到很多在网上的PHP扩展开发中,鲜有叙及的部分(比如, 实现类/接口, 继承, 自动加载,等等), 让更多的PHP扩展开发者可以借鉴.</p>
<p>    最后, 考虑到目前有很多PHP框架, 而这些框架中也有很多很优秀的代表, 比如Zend Framework(因为Yaf是依照Zf来的, 所有特指一下).  这些框架, 运用了很多PHP5以后的新技术, 那么, 如果用扩展写一个类似于她们的框架, 除了能达到我之前想要的扩展教程的目标, 又能很大程度上解决, 框架的性能问题..</p>
<p>   至于, 为什么叫Yaf, 是我实在想不到更好的名字了, 就借鉴了Yacc的命名方法, 取名为(yet another framework)</p>
<p>   Yaf本着把框架中不一遍的部分抽象出来, 并且提供灵活的可调整的接口, 实现了类似Zend Framework的如下接口/类:</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;">
Yaf_Application
Yaf_Controller
Yaf_View
Yaf_Request
Yaf_Bootstrap
Yaf_Route
Yaf_Config
Yaf_Registry
Yaf_IView
Yaf_Exception
</pre>
<p>   也采用了和ZF一样的dispatchLoop方式,  支持Bootstrap, Plugin. 当然从性能最优考虑, 改变了一些接口类和调用时刻的参数类型.</p>
<p>   具体的可以参看<a href="http://www.laruence.com/yaf/manual/" >Yaf手册</a></p>
<p>   Google Code地址: <a href="http://code.google.com/p/yafphp"  target="_blank" >phpyaf</a></p>
<p>   不过Yaf目前也只是0.1 alpha版本, 还没有经过系统测试, 所以估计Bug不少, 就暂时不推荐试用了. 等达到beta版本以后, 再请试用.</p>
<p>   目前放出, 供大家挑毛病和提建议, 也希望有兴趣的同学可以参与进来.</p>
<p>   最后, 我希望Yaf可以成为一个成功的PHP框架.. 也希望以Yaf能成为一个好的PHP扩展样板实例.<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3141" >2010/09/04</a>, Fans writes: 鸟哥威武， 百度强大啊。</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3142" >2010/09/04</a>, 夜猫子 writes: 我曾经在PHPChina上看到一个人说他打算把框架做成PHP扩展方式，当时我反对了他的看法，所以这次我也打算和您讨论一下这种做法
用扩展方式实现框架，本质基本上等于早期用C语言开发cgi，当然基于PHP的扩展就不用自己去处理HTTP这一块，而且调用上用PHP也比较便于调用
但是，我觉得之所以现在大家都不用C开发cgi，转而使用动态语言（PHP Python Ruby）等等，就是为了调试方便，部署简单
如果其他人在使用中，对框架本身什么地方觉得有问题，只能通过修改扩展的C源程序去改动，这一点您在文档里的开发难点一节也有提到
恕我直言，我认为这种做法是逆潮流而动
如果仅仅是不计成本和结果的个人兴趣，或者仅仅针对特定环境的开发，那另当别论，呵呵</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3143" >2010/09/04</a>, thinkphp writes: 夜猫子，你用PDO扩展么？没有觉得PDO包装MySQL是逆潮流而动？你用PDO的时候有问题还会自己去修改PDO的源码么？
我顶鸟哥。人家开源共享，还老有人jjww！</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3144" >2010/09/04</a>, CZ writes: Yacc的a是another的意思</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3145" >2010/09/04</a>, <a href="http://www.zhaiduo.com"  rel="external nofollow"  class="url" >zhaiduo</a> writes: 夜猫子说的很有道理</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3147" >2010/09/04</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @夜猫子  恩, 你说话是没有问题的, 只不过Yaf的遵旨是把不变的部分抽象出来, 所以说是逆流, 是不确切的.

@CZ 谢谢指正, 是我疏忽了, :)</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3148" >2010/09/05</a>, <a href="http://hi.baidu.com/mozhihuidage"  rel="external nofollow"  class="url" >烂叶</a> writes: 鸟哥期待你的源码共享</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3149" >2010/09/05</a>, <a href="http://www.phppan.com/"  rel="external nofollow"  class="url" >胖子</a> writes: 向鸟哥学习</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3150" >2010/09/05</a>, <a href="http://blog.rebill.info"  rel="external nofollow"  class="url" >Rebill</a> writes: 支持，才Alpha文档已经写得这么全了，赞一个。</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3151" >2010/09/06</a>, <a href="http://zhys9.com"  rel="external nofollow"  class="url" >zhys9</a> writes: 看了一遍文档，确实还是很期待的！不过，文档里有些地方写错了。
比如：
 （例 5.1）是不是加载(application.library.directory)}/Zend/Dummy/Foo.(application.ext)？
  6.4章应该是获取$_SERVER变量的值
都是小问题:)  不要说我鸡蛋里挑骨头呀~

赞！</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3157" >2010/09/06</a>, johnpupu writes: 是否可以在google code 上提供可以下載的版本
因為我想幫yaf送進FreeBSD的ports
若是沒辦法的話, 我會自已從trunk 上抓下來包成一個tar.gz
放到一個 public 網路空間
感謝</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3158" >2010/09/06</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @johnpupu 目前因为是alpha的版本, 不推荐试用, 所以没有提供可以打包下载的版本. 还是等稳定以后再送吧. (起码beta以后)</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3160" >2010/09/06</a>, <a href="http://www.interpretersky.com"  rel="external nofollow"  class="url" >Chinese Interpreter</a> writes: 分享创造美好~~
接触PHP时间不是很长，继续观察学习中。</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3161" >2010/09/06</a>, <a href="http://www.hdwong.com/"  rel="external nofollow"  class="url" >Bun Wong</a> writes: 顶啊！学习 PHP Extension 开发</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3162" >2010/09/06</a>, 卷卷 writes: 这个框架的实际意义是？</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3163" >2010/09/06</a>, johnpupu writes: @雪候鸟
ok~了解~ 感謝^^
另外有計畫中的roadmap 嗎?
如果有的話 ~</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3164" >2010/09/06</a>, Anonymous writes: 封面那只河蟹是干嘛的。。。</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3165" >2010/09/06</a>, xqpm writes: 有意思，但为什么借的ZF的设计思想呢？这跟你的logo貌似又冲突了哦。既然是以快为目标，那么就应该考虑丢掉MVC那一套。ROR的思想很好，我觉得应该可以考虑下:)</li><li><a href="http://www.laruence.com/2010/09/04/1736.html#comment-3167" >2010/09/06</a>, 夜猫子 writes: 我的目的不是找茬，只是提出讨论而已，相信博主是看得出来的
至于前面thinkphp提出的pdo的反驳，我的看法是这样的
拿建筑来类比我们的程序开发，从砖瓦 -&gt; 墙壁、房梁 -&gt; 楼层 -&gt; 完整建筑，是一层一层的抽象和封装
我的看法是，PHP扩展封装到砖瓦这个级别就好了，再做向上的封装就不太合适
框架在我看来，已经是一个比较高级别的封装层次了
除非能够获得数量级的效率提升，10倍或者100倍，否则投入如此多的开发时间以及复杂度提升，算起来有点亏本啊</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/09/04/1736.html/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>将PHP Manual融入(g)Vim</title>
		<link>http://www.laruence.com/2010/08/18/1718.html</link>
		<comments>http://www.laruence.com/2010/08/18/1718.html#comments</comments>
		<pubDate>Wed, 18 Aug 2010 08:46:20 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[随笔]]></category>
		<category><![CDATA[gvim]]></category>
		<category><![CDATA[manual]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[vim]]></category>
		<category><![CDATA[手册]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1718</guid>
		<description><![CDATA[首先说个题外话: Vim发布<a href="http://www.vim.org/" target="_blank">7.3</a>了..

    在翻看Vim插件的时候, 发现了一个比较有意思的应用(非插件): 把PHP的手册融如Vim中, 在Vim中, 按"K", 就可以跳转到光标下函数的手册说明...]]></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/08/18/1718.html"  title="Permanet Link to 将PHP Manual融入(g)Vim" >http://www.laruence.com/2010/08/18/1718.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
    首先说个题外话: Vim发布<a href="http://www.vim.org/"  target="_blank" >7.3</a>了..</p>
<p>    在翻看Vim插件的时候, 发现了一个比较有意思的应用(非插件): 把PHP的手册融如Vim中, 在Vim中, 按&#8221;K&#8221;, 就可以跳转到光标下函数的手册说明&#8230;</p>
<p>    1. 首先, 下载特殊定制的PHP手册(包含PHP5.3的所有函数) : <a href="http://www.interpotential.com/downloads/vim/vim-php-manual.tar.gz"  target="_blank" >vim-php-manual.tar.gz</a></p>
<p>    2. 把下载的文件解压缩, 放置到一个目录, 比如/tmp/phpmuanul(windows下比如:&#8221;d:/phpmanual&#8221;).</p>
<p>    3. 配置vimrc(linux下是.vimrc,windows下是_vimrc), 把phpmanual目录添加到runtimepath(稍后解释为什么).</p>
<p>    4. 配置vimrc, 使得keywordprg=&#8221;help&#8221;. 在我的机器上, keywordprg默认是!man, 大多数时候, 我还是希望可以直接man到linux下的标准函数库, 所以我使用(在vimrc文件中):</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;">
autocmd BufNewFile,Bufread *.ros,*.inc,*.php set keywordprg=&quot;help&quot;
</pre>
<p>    或者也可以写在vim目录下的ftplugin下的php.vim(如果没有新建), 这样在ft为php的时候,这个配置脚本就会被加载.</p>
<p>  至于说, 为什么要把phpmanual目录添加到runtimepath, 是因为:</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;">
When no argument is given to :help the file given with the 'helpfile' option
will be opened.  Otherwise the specified tag is searched for in all &quot;doc/tags&quot;
files in the directories specified in the 'runtimepath' option.
</pre>
<p>   意思就是说, 在vim中, 调用help的时候, help会去所有的runtimpath下的doc目录中寻找tags文件, 来寻找要查找的帮助关键字.</p>
<p>   在我们下载的vim-php-manual.tar.gz文件中, 就包含了doc/tags这样的文件目录结构, 所以只要把phpmanual目录加入runtimepath, 并且设置keywordprg为vim的help, 就可以实现在光标处按&#8221;K&#8221;跳转到函数手册了.<br/>
<div id="attachment_1721"  class="wp-caption aligncenter"  style="width: 310px" ><a href="http://www.laruence.com/wp-content/uploads/vim_phpmanul.png" ><img src="http://www.laruence.com/wp-content/uploads/vim_phpmanul-300x185.png"  alt=""  title="vim_phpmanul"  width="300"  height="185"  class="size-medium wp-image-1721" /></a><p class="wp-caption-text" >使用截图</p></div></p>
<p>    最后,补充一点, 如果在使用的时候,Vim提示你:</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;">
 tags file not sorted
</pre>
<p>   那你就用vim打开phpmanual/doc/tags, 然后%sort一下就可以了&#8230;<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/2010/08/18/1718.html#comment-3089" >2010/08/18</a>, <a href="http://www.youyuge.com"  rel="external nofollow"  class="url" >xiaokai</a> writes: 下班回家试试..</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3090" >2010/08/18</a>, <a href="http://www.felix021.com"  rel="external nofollow"  class="url" >felix021</a> writes: 感谢分享！ 
.tar.gz下载有点儿慢。

另外，keywordprg应该是 :help
autocmd FileType php set keywordprg=:help</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3091" >2010/08/18</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @felix021 :help和"help"(有引号)都可, :)</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3092" >2010/08/18</a>, simplechen writes: 兄弟你是用VIM的老手了，能否分享一下你的VIM配置。：） 多谢！</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3094" >2010/08/19</a>, <a href="http://topsy.com/www.laruence.com/2010/08/18/1718.html?utm_source=pingback&amp;utm_campaign=L2"  rel="external nofollow"  class="url" >Tweets that mention 将PHP Manual融入(g)Vim | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by 惠新宸, glemir and 惠新宸, Wing. Wing said: 說 http://www.plurk.com/p/70diq1 ([rep])@jaceju : http://tinyurl.com/25dqjgl (将PHP Manual融入（g）Vim) http://plurk.com/p/70igkh [...]</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3097" >2010/08/21</a>, <a href="http://www.zhangabc.com"  rel="external nofollow"  class="url" >张二</a> writes: 呵呵，试了一下，果然V5，比较懒，set runtimepath发现.vim/doc已经包含在runtimepath变量中了，由于直接cd ~/.vim,然后解压了鸟哥的包（好多文件),然后设置了一下.vimrc……很好用哦。</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3103" >2010/08/22</a>, <a href="http://www.gugeqq.com"  rel="external nofollow"  class="url" >谷哥QQ</a> writes: 感谢分享！</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3105" >2010/08/23</a>, <a href="http://www.nflfootballjerseys"  rel="external nofollow"  class="url" >nfl football jerseys</a> writes: 博主绝对是VIM高手，提供的很详细，刚试了一下，很好用，谢谢了</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3112" >2010/08/25</a>, <a href="http://www.airmaxtrainer.com"  rel="external nofollow"  class="url" >air max shoes</a> writes: 是挺慢的 不过很好用哦！</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3123" >2010/08/30</a>, <a href="http://www.js4j.com/"  rel="external nofollow"  class="url" >技术网</a> writes: 还没试用，先谢谢分享</li><li><a href="http://www.laruence.com/2010/08/18/1718.html#comment-3132" >2010/09/01</a>, <a href="http://www.olc.com.tr"  rel="external nofollow"  class="url" >Yurtdışı Eğitim</a> writes: Is this web site availible in English?</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/08/18/1718.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>注意PHP对字符串的递增运算</title>
		<link>http://www.laruence.com/2010/07/30/1682.html</link>
		<comments>http://www.laruence.com/2010/07/30/1682.html#comments</comments>
		<pubDate>Fri, 30 Jul 2010 08:04:09 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[随笔]]></category>
		<category><![CDATA[increment string]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1682</guid>
		<description><![CDATA[ 有同学问了一个问题:
<coolcode lang="php" linenum="off">
<?php
for($i = 'A'; $i <= 'Z'; $i++) {
    echo $i;
}
</coolcode>
    输出是啥?
   
   说个题外话: <a href="http://www.laruence.com">Blog</a>现在支持订阅评论了, 同学们有提问以后等我回答的, 可以在留言提问的时候, 选择:Notify me of followup comments via e-mail]]></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/07/30/1682.html"  title="Permanet Link to 注意PHP对字符串的递增运算" >http://www.laruence.com/2010/07/30/1682.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
    有同学问了一个问题:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
for($i = 'A'; $i &lt;= 'Z'; $i++) {
    echo $i;
}
</pre>
<p>    输出是啥?</p>
<p>   输出是:</p>
<blockquote><p>ABCDEFGHIJKLMNOPQRSTUVWXYZAAABACADAEAFAGAHAIAJAKALAMANAOAPAQARAS&#8230;&#8230;.</p></blockquote>
<p>    为啥?</p>
<p>    其实很简单,  PHP的手册中也有说明, 只不过恐怕很多人不会一章一节的把手册仔细阅读一遍:</p>
<blockquote><p>
     PHP follows Perl&#8217;s convention when dealing with arithmetic operations on character variables and not C&#8217;s. For example, in Perl &#8216;Z&#8217;+1 turns into &#8216;AA&#8217;, while in C &#8216;Z&#8217;+1 turns into &#8216;[&#8216; ( ord(&#8216;Z&#8217;) == 90, ord(&#8216;[&#8216;) == 91 ). Note that character variables can be incremented but not decremented and even so only plain ASCII characters (a-z and A-Z) are supported.
</p></blockquote>
<p>     在处理字符变量的算数运算时，PHP 沿袭了 Perl 的习惯，而非 C 的。例如，在 Perl 中 &#8216;Z&#8217;+1 将得到 &#8216;AA&#8217;，而在 C 中，&#8217;Z'+1 将得到 &#8216;[&#8216;（ord(&#8216;Z&#8217;) == 90，ord(&#8216;[&#8216;) == 91）。注意字符变量只能递增，不能递减，并且只支持纯字母（a-z 和 A-Z）。</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;">
$name = &quot;laruence&quot;;
++$name; //将会是&quot;laruencf&quot;
</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;">
$name = &quot;laruence&quot;;
--$name; //没有影响, 还是&quot;laruence&quot;
</pre>
<p>    所以, 这个问题的原因就是当$i = Z的时候, ++$i成了AA, 而字符串比较的话,<br/>
AA,BB,XX一直到YZ都是小于等于Z的&#8230; so..</p>
<p>    最后, 说个题外话:  <a href="http://www.laruence.com" >Blog</a>现在支持订阅评论了, 同学们有提问以后等我回答的, 可以在留言提问的时候, 选择:Notify me of followup comments via e-mail<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/07/30/1682.html#comment-3017" >2010/07/31</a>, <a href="http://www.phppan.com"  rel="external nofollow"  class="url" >胖子</a> writes: 学习了，感谢鸟哥</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3018" >2010/07/31</a>, <a href="http://www.phppan.com"  rel="external nofollow"  class="url" >胖子</a> writes: 其实说明了另一个问题：PHP中没有字符，即使用chr,返回的也是一个长度为1的字符串
如：
var_dump(chr(90));
得到：
string 'Z' (length=1)</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3020" >2010/07/31</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @胖子 这个总结挺Cool:"PHP中没有字符"</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3022" >2010/07/31</a>, <a href="http://www.jaceju.net/blog/?p=1319"  rel="external nofollow"  class="url" >網站製作學習誌 &raquo; [Web] 連結分享</a> writes: [...] 注意PHP对字符串的递增运算 [...]</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3024" >2010/08/01</a>, <a href="http://topsy.com/www.laruence.com/2010/07/30/1682.html?utm_source=pingback&amp;utm_campaign=L2"  rel="external nofollow"  class="url" >Tweets that mention 注意PHP对字符串的递增运算 | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by Angus Li, 小夜. 小夜 said: 注意PHP对字符串的递增运算 : http://goo.gl/0Koy [...]</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3027" >2010/08/02</a>, <a href="http://blog.thinkinlamp.com/?p=373"  rel="external nofollow"  class="url" >Think In LAMP Blog &raquo; Blog Archive &raquo; PHP每周通讯（20100802）</a> writes: [...] 风雪之隅　　　　　　　注意PHP对字符串的递增运算  　　　　　　　　　　　http://www.laruence.com/2010/07/30/1682.html  [...]</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3028" >2010/08/03</a>, <a href="http://www.bixuda.com/2010/08/03/%e8%bd%ac%e6%b3%a8%e6%84%8fphp%e5%af%b9%e5%ad%97%e7%ac%a6%e4%b8%b2%e7%9a%84%e9%80%92%e5%a2%9e%e8%bf%90%e7%ae%97/"  rel="external nofollow"  class="url" >[转]注意PHP对字符串的递增运算 | { yeah : 必须哒 }</a> writes: [...] 本文地址: http://www.laruence.com/2010/07/30/1682.html [...]</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3030" >2010/08/03</a>, <a href="###"  rel="external nofollow"  class="url" >江湖游医</a> writes: 大师就是大师啊.
看来很平常的问题,经过一分析原来其中还有大道理..</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3034" >2010/08/03</a>, <a href="http://hi.baidu.com/luk4u"  rel="external nofollow"  class="url" >luk4u</a> writes: 博主，您好，关注你的博客有一段时间了，感觉非常会钻研。我也有看php的c代码，memcached，nginx代码都有看过。我的博客http://hi.baidu.com/luk4u，希望多多指点我 ^^</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3039" >2010/08/04</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @luk4u 你好, 指点不敢, 有问题可以互相交流, :)</li><li><a href="http://www.laruence.com/2010/07/30/1682.html#comment-3082" >2010/08/14</a>, <a href="http://roygu.com/?p=837"  rel="external nofollow"  class="url" >php字符递增问题 | Roy Gu</a> writes: [...] = &#39;A&#39;; $i  输出竟然是&#39;AA&#39;。。。这确实让人意外，最后在laruence的博客中找到了解释，原来当$i = [...]</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/07/30/1682.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>PHP运算符优先级的一个例外</title>
		<link>http://www.laruence.com/2010/07/26/1668.html</link>
		<comments>http://www.laruence.com/2010/07/26/1668.html#comments</comments>
		<pubDate>Mon, 26 Jul 2010 09:27:43 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[operator precedence]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[运算符优先级]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1668</guid>
		<description><![CDATA[今天在老王的技术手册看到一个问题:
<coolcode lang="php" linenum="off">
<?php
if ($a = 100 &#038;& $b = 200) {
	var_dump($a, $b);
}
</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/07/26/1668.html"  title="Permanet Link to PHP运算符优先级的一个例外" >http://www.laruence.com/2010/07/26/1668.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	今天在<a href="http://hi.baidu.com/thinkinginlamp/blog/item/5e8062d9b33ccc2110df9b2a.html"  target="_blank" >老王的技术手册</a>看到一个问题:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
if ($a = 100 &amp;&amp; $b = 200) {
	var_dump($a, $b);
}
</pre>
<p>    输出是什么?</p>
<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;">
$a = (100 &amp;&amp; $b) = 200
</pre>
<p>	而实际上的结果, 确实高优先级的&#038;&#038;让步给次优先级的=, 让 $b = 200 先结合了. </p>
<p>	究其原因, 是因为PHP并不完全遵守优先级的定义, 这个在PHP的手册中也有说明:</p>
<blockquote><p>
Note: Although = has a lower precedence than most other operators, PHP will still allow expressions similar to the following: if (!$a = foo()), in which case the return value of foo() is put into $a.
</p></blockquote>
<p>	这样的设计, 个人不发表看法, 反正在C语言中, 这样类似的语句是判定为语法错的. PHP采用这样的设计, 很可能是历史原因, </p>
<p>	有好奇的同学, 会想知道到底为什么, 之前jayeeliu网友也问过:</p>
<blockquote><p>
laruence你好：<br/>
	问一个php运算符优先级的问题<br/>
		$t == 1 &#038;&#038; $tt = 2<br/>
	按照php运算符优先级应该是<br/>
		(($t == 1) &#038;&#038; $tt) = 2<br/>
	这个顺序执行，但实际上应该是<br/>
		($t == 1) &#038;&#038; ($tt = 2)<br/>
	我有些不太理解。
</p></blockquote>
<p>  	其实也简单, 运算符优先级是在存在二义性文法的时候的一种规约规则选择的手段,  而PHP的语法分析文件定义中, 却让等号和T_BOOLEAN_AND(&#038;&#038;)之前不存在了规约冲突:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
expr_without_variable:
  // 有隐规则存在, 相当于T_BOOLEAN_AND成为了&quot;一元操作符&quot;.
  |   expr T_BOOLEAN_AND  { zend_do_boolean_and_begin(&amp;$1, &amp;$2 TSRMLS_CC); } expr
</pre>
<p>      最后, 顺便说一下, PHP对应于T_BOOLEAN_AND 还定义了 T_LOGICAL_AND(and) 和 T_LOGICAL_OR(or) , 这俩个的优先级都低于等号, 于是就会有了, 很多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;">
$result = mysql_query(*)  or die(mysql_error());
</pre>
<p>	类似的还可以用or来实现三元操作符(?:)的功能:</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;">
	$person = $who or $person = &quot;laruence&quot;;
//等同于:
	$person = empty($who)? &quot;laruence&quot; : $who;
</pre>
<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_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></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/07/26/1668.html#comment-2988" >2010/07/26</a>, <a href="http://www.blogismoney.net"  rel="external nofollow"  class="url" >半醒</a> writes: mysql connect那语句的确很经典

这种优先级的约束能不能认为是更符合人的自然思维？</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-2989" >2010/07/26</a>, <a href="http://t.sina.com.cn/liruqi"  rel="external nofollow"  class="url" >liruqi</a> writes: 这种问题挺tricky
还是尽量避免magic code比较方便。</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-2990" >2010/07/26</a>, <a href="http://test"  rel="external nofollow"  class="url" >yyj</a> writes: 

alert('ddd');
</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-2991" >2010/07/26</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @yyj 你想xss我? 太坏了..</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-2994" >2010/07/27</a>, anyharding writes: 为什么要写歧义代码，加上小括号不就好了吗？
代码是让人读的，提高可读性的同时，也避免犯一些错误</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-2995" >2010/07/27</a>, <a href="http://www.jingying.org.cn/"  rel="external nofollow"  class="url" >火跃</a> writes: 不错！学习了！</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-2998" >2010/07/27</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @anyharding 我们可以要求自己的代码易读, 但无法保证别人的代码. :)</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-3019" >2010/07/31</a>, <a href="http://www.yeeger.com/?p=144"  rel="external nofollow"  class="url" >PHP运算符的两个问题 | yeeger.com</a> writes: [...] 本文地址: http://www.laruence.com/2010/07/26/1668.html [...]</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-3021" >2010/07/31</a>, <a href="http://www.jaceju.net/blog/?p=1319"  rel="external nofollow"  class="url" >網站製作學習誌 &raquo; [Web] 連結分享</a> writes: [...] PHP运算符优先级的一个例外 [...]</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-3023" >2010/07/31</a>, <a href="http://www.paitoubing.cn"  rel="external nofollow"  class="url" >排头兵</a> writes: 受教，呵呵。

优先级 ！！！</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-3026" >2010/08/02</a>, <a href="http://blog.thinkinlamp.com/?p=373"  rel="external nofollow"  class="url" >Think In LAMP Blog &raquo; Blog Archive &raquo; PHP每周通讯（20100802）</a> writes: [...] 风雪之隅　　　　　　　PHP运算符优先级的一个例外  　　　　　　　　　　　http://www.laruence.com/2010/07/26/1668.html  [...]</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-3099" >2010/08/21</a>, <a href="http://www.coderbolg.com"  rel="external nofollow"  class="url" >蓝色夏威夷</a> writes: 额，有意思啊。</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-3125" >2010/08/31</a>, <a href="http://www.166ck.com"  rel="external nofollow"  class="url" >Audio</a> writes: 以前还一直没遇到过这种情况，受教了！以后写代码还是要多按标准写！</li><li><a href="http://www.laruence.com/2010/07/26/1668.html#comment-3159" >2010/09/06</a>, <a href="http://www.hdwong.com/"  rel="external nofollow"  class="url" >Bun Wong</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/2010/07/26/1668.html/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>PHP调试技术手册发布(1.0.0 pdf)</title>
		<link>http://www.laruence.com/2010/06/21/1608.html</link>
		<comments>http://www.laruence.com/2010/06/21/1608.html#comments</comments>
		<pubDate>Mon, 21 Jun 2010 05:31:22 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[手册]]></category>
		<category><![CDATA[调试技术]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1608</guid>
		<description><![CDATA[   <a href="http://blog.csdn.net/heiyeshuwu" target="_blank">黑夜路人</a>前段时间, 本着分享/总结的精神, 计划要总结下PHP常用的调试技术, 就一些问题找到了我..

   如今第一版的PHP调试技术手册已经发布.

   冠以我名, 我甚感惶恐, 只能一并赞下小黑的nice了~

   下载地址: <a href="http://heiyeluren-doc.googlecode.com/files/PHP-Debug-Manual-public.pdf">http://heiyeluren-doc.googlecode.com/files/PHP-Debug-Manual-public.pdf</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/2010/06/21/1608.html"  title="Permanet Link to PHP调试技术手册发布(1.0.0 pdf)" >http://www.laruence.com/2010/06/21/1608.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   <a href="http://blog.csdn.net/heiyeshuwu"  target="_blank" >黑夜路人</a>前段时间, 本着分享/总结的精神, 计划要总结下PHP常用的调试技术, 就一些问题找到了我..</p>
<p>   如今第一版的PHP调试技术手册已经发布.</p>
<p>   冠以我名, 我甚感惶恐, 只能一并赞下小黑的nice了~</p>
<p>   下载地址: <a href="http://heiyeluren-doc.googlecode.com/files/PHP-Debug-Manual-public.pdf" >http://heiyeluren-doc.googlecode.com/files/PHP-Debug-Manual-public.pdf</a></p>
<p>   目录:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1 内置API输出调试
1.1 基本调试API
1.1.1 echo (print):
1.1.2 printf
1.1.3 print_r、var_dump(var_export)、debug_zval_dump
1.2 错误控制和日志记录调试
1.2.1 错误选项控制
1.2.2 错误抛出和处理
1.2.3 使用错误抑制符
1.2.4 日志记录
2 浏览器调试
2.1 页面输出调试
2.2 FirePHP  调试
2.2.1 普通变量监测
2.2.2 调用栈监测
2.2.3 监测抛出异常
2.2.4 组显示信息
3 IDE 调试
3.1 基本常用IDE介绍
3.1.1 Vim
3.1.2 Zend Studio
3.1.3 Eclipse
3.1.4 NetBeans
3.2 IDE调试
3.2.1 Zend Studio + Zend Debugger
3.2.2 Eclipse (PDT) + Xdebug
3.2.3 Vim + Xdebug + DBGp
4 PHP 性能调试技术
4.1 基本时间占用监测
4.2 使用  Xdebug 进行性能分析
4.2.1 安装配置：
4.3 APD(Advanced PHP Debugger)
4.3.1 安装配置
4.3.2 使用APD
4.4 使用Xhprof 进行性能分析
4.4.1 Xhprof  的优点：
5 PHP单元测试技术
5.1 PHPUnit
</pre>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2771" >2010/06/21</a>, 小熊 writes: 阅</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2772" >2010/06/21</a>, <a href="http://www.zvv.cn"  rel="external nofollow"  class="url" >zwws</a> writes: 好东西, 已经发到部门共享了, 赞一个!</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2773" >2010/06/21</a>, <a href="http://www.xinqdian.com"  rel="external nofollow"  class="url" >小宝</a> writes: 这个绝对得支持下！</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2774" >2010/06/21</a>, qxhy123 writes: 迅速插入前5</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2775" >2010/06/21</a>, marker writes: 顶呀</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2776" >2010/06/21</a>, <a href="http://topsy.com/www.laruence.com/2010/06/21/1608.html?utm_source=pingback&amp;utm_campaign=L2"  rel="external nofollow"  class="url" >Tweets that mention PHP调试技术手册发布(1.0.0 pdf) | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by icyleaf, cunsheng. cunsheng said: PHP调试技术手册发布(1.0.0 pdf) http://ff.im/-mqIlL [...]</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2777" >2010/06/21</a>, <a href="http://www.youyuge.com"  rel="external nofollow"  class="url" >xiaokai</a> writes: 来的还不算晚..</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2779" >2010/06/21</a>, <a href="http://sychen.org"  rel="external nofollow"  class="url" >sychen</a> writes: 顶，值得拜读~</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2780" >2010/06/21</a>, <a href="http://lepingbeta.com"  rel="external nofollow"  class="url" >Symphony</a> writes: 超赞，这个不能不顶啊。。。</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2781" >2010/06/21</a>, <a href="http://www.9enjoy.com"  rel="external nofollow"  class="url" >9enjoy</a> writes: 好东西，学习一下。</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2783" >2010/06/21</a>, <a href="http://glemir.xplore.cn"  rel="external nofollow"  class="url" >glemir</a> writes: 很给力啊，老湿</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2785" >2010/06/21</a>, <a href="http://hjin.me"  rel="external nofollow"  class="url" >HJin.me</a> writes: 作为一个php学习生，看到这样的好东西，自然留言以表示对博主的感谢～～～</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2788" >2010/06/22</a>, <a href="http://0xs.cn/"  rel="external nofollow"  class="url" >潇洒</a> writes: 呵呵~ 既然收了，就得留个脚印...
不知有木有时间看哈...</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2831" >2010/06/23</a>, <a href="http://www.zhangabc.com"  rel="external nofollow"  class="url" >yufeng</a> writes: 学习啊，特别是vim调试那节，找个时间实验一下，有时var_dump\print_r真的很烦。</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2834" >2010/06/23</a>, <a href="http://www.pentestday.com/2010/06/php-debug-manual-version-1-0-0.html"  rel="external nofollow"  class="url" >PHP调试技术手册 | Pentestday</a> writes: [...] v1.0.0 Posted on June 23, 2010 by xi4oyu* 作者: laruence(http://www.laruence.com) * 本文地址: http://www.laruence.com/2010/06/21/1608.html * 转载请注明出处黑夜路人前段时间, 本着分享/总结的精神, [...]</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2835" >2010/06/24</a>, <a href="http://www.mkrss.com/?p=52"  rel="external nofollow"  class="url" >PHP调试技术手册发布(1.0.0 pdf) &laquo; Yet another wordpress blog</a> writes: [...] 本文地址: http://www.laruence.com/2010/06/21/1608.html [...]</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2840" >2010/06/24</a>, z.En writes: 很有用</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2842" >2010/06/24</a>, <a href="http://www.pentestday.com"  rel="external nofollow"  class="url" >xi4oyu</a> writes: 顶，转载了</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2850" >2010/06/27</a>, <a href="http://www.zhangabc.com/?p=142"  rel="external nofollow"  class="url" >ZhangABC.com &raquo; 向printechovar_dump说再见,用VIM来调试PHP程序</a> writes: [...] &gt;(详见鸟哥此文，强力推荐). [...]</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2864" >2010/06/29</a>, <a href="http://sanmuding.com"  rel="external nofollow"  class="url" >Anders</a> writes: 呵呵，好怀念PHP阿。</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2867" >2010/07/01</a>, <a href="http://www.yakecan.com/archives/386"  rel="external nofollow"  class="url" >&raquo; Creative Power</a> writes: [...] 原文地址: http://www.laruence.com/2010/06/21/1608.html [...]</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2869" >2010/07/02</a>, <a href="http://xiaobin.net/201007/using-vim-and-xdebug-to-debug-php-code/"  rel="external nofollow"  class="url" >Vim+XDebug调试PHP | 将之典藏</a> writes: [...] 感谢老黑和鸟哥发布的《PHP调试指南》(via)。要不是他们，我可能还在用echo/var_dump调试PHP代码。是他们解救了我，引导我走向光明，感激涕零中……本文是对指南中的《Vim + Xdebug + DBGp》一章的一些补充。 [...]</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2886" >2010/07/06</a>, Luffy writes: 一口氣看完~真的很讚, 若果UNIT TEST都可以寫得詳盡點就完美了.</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2908" >2010/07/09</a>, <a href="http://www.js4j.com/"  rel="external nofollow"  class="url" >技术论坛</a> writes: 拜读</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2942" >2010/07/16</a>, <a href="http://dothing"  rel="external nofollow"  class="url" >lake</a> writes: 非常好，收藏了。多谢高手的分享。</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-2964" >2010/07/19</a>, <a href="http://www.ezsky.org"  rel="external nofollow"  class="url" >ezsky</a> writes: 收藏了!
支持,感谢.</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-3096" >2010/08/21</a>, <a href="http://blog.pptpb.org/2010/08/21/337"  rel="external nofollow"  class="url" >雨季來了 &raquo; link notes</a> writes: [...] PHP調試技術手冊 [...]</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-3113" >2010/08/25</a>, <a href="http://www.bestfinance-blog.com"  rel="external nofollow"  class="url" >CarissaAlford27</a> writes: That is cool that people are able to receive the <a href="http://bestfinance-blog.com/topics/home-loans"  rel="nofollow" >home loans</a> moreover, that opens completely new opportunities.</li><li><a href="http://www.laruence.com/2010/06/21/1608.html#comment-3114" >2010/08/26</a>, <a href="http://www.airmaxtrainer.com"  rel="external nofollow"  class="url" >air max shoes</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/2010/06/21/1608.html/feed</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>深入理解PHP之匿名函数</title>
		<link>http://www.laruence.com/2010/06/20/1602.html</link>
		<comments>http://www.laruence.com/2010/06/20/1602.html#comments</comments>
		<pubDate>Sun, 20 Jun 2010 14:41:58 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[anonymous function]]></category>
		<category><![CDATA[closure]]></category>
		<category><![CDATA[create_function]]></category>
		<category><![CDATA[lambda function]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[匿名函数]]></category>
		<category><![CDATA[闭包]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1602</guid>
		<description><![CDATA[	PHP中, 传递Callback的方式, 一直很丑陋. 在PHP5.3以前, 我们只有俩种选择:
<coolcode lang="bash" linenum="off">
1. 字符串的函数名
2. 使用create_function的返回值
</coolcode>
	在PHP5.3以后, 我们多了一个选择, 也就是Closure, 
<coolcode lang="php" linenum="off">
$func = function () { ... };
array_walk($arr, $func);
</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/06/20/1602.html"  title="Permanet Link to 深入理解PHP之匿名函数" >http://www.laruence.com/2010/06/20/1602.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	PHP中, 传递Callback的方式, 一直很丑陋. 在PHP5.3以前, 我们只有俩种选择:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. 字符串的函数名
2. 使用create_function的返回值
</pre>
<p>	在PHP5.3以后, 我们多了一个选择, 也就是Closure, </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;">
$func = function () { ... };
array_walk($arr, $func);
</pre>
<p>	从实现上来说, 第一种方式: 传递函数名字符串是最简单的.</p>
<p>	而第二种方式create_function, 其实和第一种方式本质上一样的, create_function返回一个字符串的函数名, 这个函数名的格式是:</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;">
&quot;\000_lambda_&quot; . count(anonymous_functions)++;
</pre>
<p>	我们来看看create_function的实现步骤:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. 获取参数, 函数体
2. 拼凑一个&quot;function __lambda_func (参数) { 函数体;} &quot;的字符串
3. eval之
4. 通过__lambda_func在函数表中找到eval后得到的函数体, 找不到就出错
5. 定义一个函数名:&quot;\000_lambda_&quot; . count(anonymous_functions)++
6. 用新的函数名替换__lambda_func
7. 返回新的函数名
</pre>
<p>	我们来验证下:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
create_function(&quot;&quot;, 'echo __FUNCTION__;');
call_user_func(&quot;\000lambda_1&quot;, 1);
?&gt;
//输出
__lambda_func
</pre>
<p>	因为在eval的时候, 函数名是&#8221;__lambda_func&#8221;, 所以匿名函数内会输出__lambda_func, 而因为最后用&#8221;\000_lambda_&#8221; . count(anonymous_functions)++重命名了函数表中的&#8221;__lambda_func&#8221;函数, 所以可通过&#8221;\000_lambda_&#8221; . count(anonymous_functions)++调用这个匿名函数.</p>
<p>	为了证实这一点, 可以将create_function的返回值dump出来查看.</p>
<p>	而在PHP5.3发布的时候, 其中有一条new feature就是支持闭包/Lambda Function, 我第一反应是以为zval新增了一个IS_FUNCTION, 但实际上是构造了一个PHP5.3引入的Closure&#8221;类&#8221;的实例, Closure类的构造函数是私有的, 所以不能被直接实例化, 另外Closure类是Final类, 所以也不能做为基类派生子类.</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-5.3.0
$class = new ReflectionClass(&quot;Closure&quot;);
var_dump($class-&gt;isInternal());
var_dump($class-&gt;isAbstract() );
var_dump($class-&gt;isFinal());
var_dump($class-&gt;isInterface());
//输出:
bool(true)
bool(false)
bool(true)
bool(false)
?&gt;
</pre>
<p>	而PHP5.3中对闭包的支持, 也仅仅是把要保持的外部变量, 做为Closure对象的&#8221;Static属性&#8221;(并不是普通意义上的可遍历/访问的属性).</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-5.3.0
$b = &quot;laruence&quot;;
$func = function($a) use($b) {};
var_dump($func);
/* 输出:
object(Closure)#1 (2) {
  [&quot;static&quot;]=&gt;
  array(1) {
    [&quot;b&quot;]=&gt;
    string(8) &quot;laruence&quot;
  }
  [&quot;parameter&quot;]=&gt;
  array(1) {
    [&quot;$a&quot;]=&gt;
    string(10) &quot;&lt;required&gt;&quot;
  }
}
*/
</pre>
<p>     这个实现, 个人认为和JS对闭包的支持比起来, 还是有些太简陋了~<br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_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><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/06/20/1602.html#comment-2767" >2010/06/20</a>, <a href="http://www.elmerzhang.com"  rel="external nofollow"  class="url" >ElmerZhang</a> writes: 第二种方式create_function 的代码贴错了吧？</li><li><a href="http://www.laruence.com/2010/06/20/1602.html#comment-2768" >2010/06/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @ElmerZhang 没有啊? 你是指哪里错了?</li><li><a href="http://www.laruence.com/2010/06/20/1602.html#comment-2770" >2010/06/21</a>, <a href="http://www.elmerzhang.com"  rel="external nofollow"  class="url" >ElmerZhang</a> writes: 不好意思，是我看错了，呵呵</li><li><a href="http://www.laruence.com/2010/06/20/1602.html#comment-2784" >2010/06/21</a>, <a href="http://syre.blogbus.com"  rel="external nofollow"  class="url" >神仙</a> writes: 底子差，没办法。</li><li><a href="http://www.laruence.com/2010/06/20/1602.html#comment-2829" >2010/06/22</a>, wynn writes: Closure机制的编写者在RFC里有提到这个问题，基本意思就是说这方面不是PHP的核心机制，因此不会在这方面下太多力气。</li><li><a href="http://www.laruence.com/2010/06/20/1602.html#comment-2836" >2010/06/24</a>, <a href="http://www.mkrss.com/?p=53"  rel="external nofollow"  class="url" >深入理解PHP之匿名函数 &laquo; Yet another wordpress blog</a> writes: [...] 本文地址: http://www.laruence.com/2010/06/20/1602.html [...]</li><li><a href="http://www.laruence.com/2010/06/20/1602.html#comment-2837" >2010/06/24</a>, <a href="http://www.jaceju.net/blog/?p=1245"  rel="external nofollow"  class="url" >網站製作學習誌 &raquo; [Web] 連結分享</a> writes: [...] 深入理解PHP之匿名函数 [...]</li><li><a href="http://www.laruence.com/2010/06/20/1602.html#comment-3029" >2010/08/03</a>, <a href="http://www.yeeger.com/?p=167"  rel="external nofollow"  class="url" >深入理解PHP之匿名函数 | yeeger.com</a> writes: [...] 转自： http://www.laruence.com/2010/06/20/1602.html     发表评论 | Trackback   2010年8月3日 | 归档于 编程高手  标签: PHP, 匿名函数, 闭包      &laquo; MyISAM和InnoDB两种引擎的区别       本文目前尚无任何评论. [...]</li><li><a href="http://www.laruence.com/2010/06/20/1602.html#comment-3139" >2010/09/04</a>, <a href="http://www.bestfinance-blog.com"  rel="external nofollow"  class="url" >Farmer18Concepcion</a> writes: One understands that men's life seems to be not cheap, but different people require money for different stuff and not every one earns big sums cash. Therefore to receive some <a href="http://bestfinance-blog.com"  rel="nofollow" >loan</a> or consolidation loans should be a proper way out.</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/06/20/1602.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>PHP错误抑制符(@)导致引用传参失败的Bug</title>
		<link>http://www.laruence.com/2010/05/28/1565.html</link>
		<comments>http://www.laruence.com/2010/05/28/1565.html#comments</comments>
		<pubDate>Fri, 28 May 2010 14:27:58 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[@]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[refer]]></category>
		<category><![CDATA[send_ref]]></category>
		<category><![CDATA[send_var_no_ref]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1565</guid>
		<description><![CDATA[今天cici网友发来一个问题, 说是在函数调用参数前面使用错误抑制符号(@)的时候, 貌似引用传参就失效了. 他想让我帮他解答为什么.

     看下面的例子:
<coolcode lang="php" linenum="off">
.....
</coolcode>

  这个问题, 我之前没有遇到过, 所以首先去找找相关资料, 看看有没有现成的答案, Goolge了一番, 发现虽然有人已经向PHP报了类似的Bug:<a href="http://bugs.php.net/bug.php?id=47623" target="_blank">http://bugs.php.net/bug.php?id=47623</a>, 但PHP官方还没有解决, 也没有给出答复.

   没办法, 只能自己分析了...]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2010/05/28/1565.html"  title="Permanet Link to PHP错误抑制符(@)导致引用传参失败的Bug" >http://www.laruence.com/2010/05/28/1565.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
     今天cici网友发来一个问题, 说是在函数调用参数前面使用错误抑制符号(@)的时候, 貌似引用传参就失效了. 他想让我帮他解答为什么.</p>
<p>     看下面的例子:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
$array = array(1,2,3);

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

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

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

//此处走了ZEND_SEND_VAL分支
non_empty_function_call_parameter_list:
        expr_without_variable   { ....} //错误的走了这个分支
    |   variable                {..... } //正常情况下
</pre>
<p>   所以导致在编译期间, 生成了不同的OPCODE, 也导致了问题的表象. </p>
<p>   最后, 我已经把原因在PHP的这个bug页做了说明, 有兴趣的可以去看看我的烂英语水平.  最后谢谢cici网友提供的这个有趣的问题.<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/05/28/1565.html#comment-2695" >2010/05/29</a>, <a href="http://www.jaceju.net/blog/?p=1196"  rel="external nofollow"  class="url" >網站製作學習誌 &raquo; [Web] 連結分享</a> writes: [...] PHP錯誤抑制符(@)導致引用傳參失敗的Bug [...]</li><li><a href="http://www.laruence.com/2010/05/28/1565.html#comment-2698" >2010/06/01</a>, 小熊 writes: 长知识了，劳伦斯大叔威武</li><li><a href="http://www.laruence.com/2010/05/28/1565.html#comment-2730" >2010/06/10</a>, <a href="http://www.sjade.com"  rel="external nofollow"  class="url" >互联生活网</a> writes: 长知识了，</li><li><a href="http://www.laruence.com/2010/05/28/1565.html#comment-3010" >2010/07/30</a>, <a href="http://www.commentset.com"  rel="external nofollow"  class="url" >mahone</a> writes: 错误抑制符是这样用的？add(@$array);
不是用在函数前面的么？@add($array);
望求教</li><li><a href="http://www.laruence.com/2010/05/28/1565.html#comment-3012" >2010/07/30</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @mahone 有的时候, 我们引用一个数组的元素的时候, 这个数组元素可能不存在, 我们为了避免它notice, 就会采用 func(@$array['key']);</li><li><a href="http://www.laruence.com/2010/05/28/1565.html#comment-3013" >2010/07/30</a>, <a href="http://www.commentset.com"  rel="external nofollow"  class="url" >mahone</a> writes: @雪候鸟
这样的啊，那isset这样判断下不好么？
如果不判断穿进去，那是去函数里面判断了是吧 ？</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/05/28/1565.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>PHP类型转换相关的一个Bug</title>
		<link>http://www.laruence.com/2010/05/26/1541.html</link>
		<comments>http://www.laruence.com/2010/05/26/1541.html#comments</comments>
		<pubDate>Wed, 26 May 2010 06:45:15 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php源码分析]]></category>
		<category><![CDATA[type cast]]></category>
		<category><![CDATA[类型转换]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1541</guid>
		<description><![CDATA[ PHP为了避免数字索引和数字字符串索引(注1)的混乱, 引入了zend_symtable_*系列函数, 并应用于数组中.
  
   这样一来, 数字字符串索引也就会被当作数字索引, 然而总是有一些情况, 是PHP的维护者没有想到的...

   比如, 类型转换时刻.]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: laruence(<a href="http://www.laruence.com"  title="风雪之隅"  target="_blank" >http://www.laruence.com</a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2010/05/26/1541.html"  title="Permanet Link to PHP类型转换相关的一个Bug" >http://www.laruence.com/2010/05/26/1541.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   PHP为了避免数字索引和数字字符串索引(注1)的混乱, 引入了zend_symtable_*系列函数, 并应用于数组中.</p>
<p>   这样一来, 数字字符串索引也就会被当作数字索引, 然而总是有一些情况, 是PHP的维护者没有想到的&#8230;</p>
<p>   比如, 类型转换时刻:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
鉴于很多朋友好心的提示, 使用json_deocde的第二个参数就可以直接得到数组.
我说明下, 如下的代码是我有意而为之, 并不是为了json_decode, 而是为了构造一个&quot;有问题&quot;的数组.
</pre>
<p> 在PHP5.2.*下(json version	1.2.1):</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">

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

$value = json_encode($data);
$obj   = json_decode($value);
$arr   = (array)$obj;
var_dump($arr);
</pre>
<p>   另<a href="http://syre.blogbus.com/"  target="_blank" >神仙</a>提供了如下的更简单的构造方法:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
$obj=new stdClass;
$obj-&gt;{'123'} = &quot;laruence&quot;;
$arr = (array)$obj;
var_dump($arr);
</pre>
<p>   此时, 问题就出现了, 上面得到的输出是:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
array(1) {
  [&quot;123&quot;]=&gt;
  string(8) &quot;laruence&quot;
}
</pre>
<p>   现在,你郁闷吧, 因为数组键是字符串, 而通过正常渠道访问的时候, PHP都会自动把数字字符串转换成数字, 所以:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
print_r($arr[123]);
//PHP Notice:  Undefined offset:  123 in ***
print_r($arr[&quot;123&quot;]);
//PHP Notice:  Undefined offset:  123 in ***
var_dump(array_key_exists(&quot;123&quot;, $arr));
//bool(false)
</pre>
<p>  我已经报了Bug, 不过PHP本身也不保证类型转换的一致性, 所以PHP维护者最后认为是不是Bug都无所谓了, 大家平时注意即可:<a href="http://bugs.php.net/bug.php?id=51915"  target="_blank" >http://bugs.php.net/bug.php?id=51915</a> </p>
<p><b>注1</b></p>
<p> 本文中所说的字符串数字和之前的文章<a href="http://www.laruence.com/2009/02/21/662.html"  target="_blank" >PHP字符串比较</a>中所说的numeric string有一点不同, 在zend_symtable_*系列函数中, 只会吧/^-?[^0][0-9]*$/这样的字符串认为是数字字符串. 相关核心逻辑如下:</p>
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
#define HANDLE_NUMERIC(key, length, func) {
    register char *tmp=key;
    if (*tmp=='-') {
        tmp++;
    }
    if ((*tmp&gt;='0' &amp;&amp; *tmp&lt;='9')) do {
        char *end=key+length-1;
        long idx;
        if (*tmp++=='0' &amp;&amp; length&gt;2) {
            break;
        }
        while (tmp&lt;end) {
            if (!(*tmp&gt;='0' &amp;&amp; *tmp&lt;='9')) {
                break;
            }
            tmp++;
        }
        if (tmp==end &amp;&amp; *tmp=='0') {
            if (*key=='-') {
                idx = strtol(key, NULL, 10);
                if (idx!=LONG_MIN) {
                    return func;
                }
            } else {
                idx = strtol(key, NULL, 10);
                if (idx!=LONG_MAX) {
                    return func;
                }
            }
        }
    } while (0);
}
</pre>
<p>  <b>PS</b>:我这里只有5.2.8, 5.2.11俩个版本, 各位读者如果有其他版本的PHP, 帮忙测试下是否在你的版本下也存在这个问题. 谢谢</p>
<p>  另: 谢谢<a href="http://www.cppblog.com/qywyh"  target="_blank" >远豪</a>提供这个问题, 原问题是和Memcached相关的.<br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2666" >2010/05/26</a>, <a href="http://skiyo.cn"  rel="external nofollow"  class="url" >Jessica</a> writes: 鸟哥 decode的时候多价格参数 不要返回object 直接返回成数组..

$arr = json_decode($value, true)</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2667" >2010/05/26</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @jessica 我是处心积虑的特意这么做的,为了构造这么个数组, 呵呵</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2668" >2010/05/26</a>, <a href="http://skiyo.cn"  rel="external nofollow"  class="url" >Jessica</a> writes: 是我误会鸟哥了..汗</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2669" >2010/05/26</a>, <a href="http://micy.cn/blog/"  rel="external nofollow"  class="url" >bunnyq</a> writes: 5.3.2下也是这个结果</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2670" >2010/05/26</a>, .... writes: $data = array(
    123 =&gt; 'laruence',
);
var_dump($data);

这时候就打印不出来了，还需要转换么？</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2671" >2010/05/26</a>, <a href="http://blog.imxifs.info"  rel="external nofollow"  class="url" >xifs</a> writes: 5.3.2也如此</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2672" >2010/05/26</a>, noknow writes: 多看手册没坏处的！</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2717" >2010/06/07</a>, <a href="http://syre.blogbus.com"  rel="external nofollow"  class="url" >神仙</a> writes: 有个更简单的构造办法
$obj=new stdClass;
$obj-&gt;{'123'} = 1;
$arr = (array)$obj;
var_dump($arr);</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2718" >2010/06/07</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @神仙 赞, 我还真没想到能这么做. ;)</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2731" >2010/06/10</a>, <a href="http://www.mmyuqi.com"  rel="external nofollow"  class="url" >两性解答</a> writes: 还需要转换么？</li><li><a href="http://www.laruence.com/2010/05/26/1541.html#comment-2848" >2010/06/26</a>, <a href="http://%/zzdwsyg1"  rel="external nofollow"  class="url" >BILLY</a> writes: <strong>PillSpot.org. Canadian Health&amp;Care.Special Internet Prices.No prescription online pharmacy.Pillspot.org.<b> <a href="http://pillspot.org/products/vitamins_herbal_supplements/ Vitamins@buy.online"  rel="nofollow" >.</a>...</strong>

Categories: <b>Stop SmokingMental HealthVitamins/Herbal Supplements.Anxiety/Sleep Aid.Antidiabetic.Eye Care.Antiviral.Antibiotics.Stomach.Blood Pressure/Heart.Antidepressants.Pain Relief.Womens Health.Anti-allergic/Asthma.Skin Care.Mens Health.Weight...</li></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/05/26/1541.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Nginx + PHP CGI的一个可能的安全漏洞</title>
		<link>http://www.laruence.com/2010/05/20/1495.html</link>
		<comments>http://www.laruence.com/2010/05/20/1495.html#comments</comments>
		<pubDate>Thu, 20 May 2010 10:13:15 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php源码分析]]></category>
		<category><![CDATA[安全漏洞]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1495</guid>
		<description><![CDATA[现在普遍的Nginx + PHP cgi的做法是在配置文件中,　通过正则匹配(<a href="" target="_blank">Nginx(PHP/fastcgi)的PATH_INFO问题</a>)设置SCRIPT_FILENAME,  今天<a href="http://www.80sec.com/" target="_blank">小顿</a>发现了一个这种方式的安全漏洞.

   比如, 有http://www.laruence.com/fake.jpg, 那么通过构造如下的URL, 就可以看到fake.jpg的二进制内容:
<coolcode lang="bash" linenum="off">
http://www.laruence.com/fake.jpg/foo.php
</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/05/20/1495.html"  title="Permanet Link to Nginx + PHP CGI的一个可能的安全漏洞" >http://www.laruence.com/2010/05/20/1495.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   现在普遍的Nginx + PHP cgi的做法是在配置文件中,　通过正则匹配(<a href=""  target="_blank" >Nginx(PHP/fastcgi)的PATH_INFO问题</a>)设置SCRIPT_FILENAME,  今天<a href="http://www.80sec.com/"  target="_blank" >小顿</a>发现了一个这种方式的安全漏洞.</p>
<p>   比如, 有http://www.laruence.com/fake.jpg, 那么通过构造如下的URL, 就可以看到fake.jpg的二进制内容:</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;">

http://www.laruence.com/fake.jpg/foo.php
</pre>
<p>   为什么会这样呢?</p>
<p>   比如, 如下的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_pass   127.0.0.1:9000;
	fastcgi_index  index.php;

	set $script    $uri;
	set $path_info &quot;&quot;;
	if ($uri ~ &quot;^(.+\.php)(/.*)&quot;) {
		set  $script     $1;
		set  $path_info  $2;
	}

	include       fastcgi_params;
	fastcgi_param SCRIPT_FILENAME   $document_root$script;
	fastcgi_param SCRIPT_NAME       $script;
	fastcgi_param PATH_INFO         $path_info;
}
</pre>
<p>   通过正则匹配以后, SCRIPT_NAME会被设置为&#8221;fake.jpg/foo.php&#8221;, 继而构造成SCRIPT_FILENAME传递个PHP CGI, 但是PHP又为什么会接受这样的参数, 并且把a.jpg解析呢?</p>
<p>   这就要说到PHP的cgi SAPI中的参数, 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;">
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PATH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix it's paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
cgi.fix_pathinfo=1
</pre>
<p>   如果开启了这个选项, 那么就会触发在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 the file doesn't exist, try to extract PATH_INFO out
 * of it by stat'ing back through the '/'
 * this fixes url's like /info.php/test
 */
if (script_path_translated &amp;&amp;
	(script_path_translated_len = strlen(script_path_translated)) &gt; 0 &amp;&amp;
	(script_path_translated[script_path_translated_len-1] == '/' ||
....//以下省略.
</pre>
<p>   到这里, PHP会认为SCRIPT_FILENAME是fake.jpg, 而foo.php是PATH_INFO, 然后PHP就把fake.jpg当作一个PHP文件来解释执行&#8230; So&#8230;</p>
<p>   这个隐患的危害用小顿的话来说, 是巨大的.</p>
<p>   对于一些论坛来说, 如果上传一个图片(实际上是恶意的PHP脚本), 继而构造这样的访问请求&#8230;</p>
<p>   所以, 大家如果有用这种服务器搭配的, 请排查, 如果有隐患, <b>请关闭fix_pathinfo(默认是开启的)</b>. </p>
<p>   详细漏洞信息, 请移步小顿的BLOG: <a href="http://www.80sec.com/nginx-securit.html"  target="_blank" >80Sec</a></p>
<p>   <b>另: 我认为这个和Nginx没啥关系, 不属于Nginx的漏洞. 是配置的问题, 现在到处都在说是Nginx的Bug, 不妥不妥.</b><br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_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_c.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2592" >2010/05/20</a>, <a href="http://www.54chen.com/php-tech/nginx-php-cgi-of-security-hole.html"  rel="external nofollow"  class="url" >[警示]Nginx + PHP CGI的安全漏洞：fix_pathinfo - 五四陈科学院-坚信科学,分享技术</a> writes: [...] 临近下班，见到鸟哥的一则php漏洞说明，具体说明在 http://www.laruence.com/2010/05/20/1495.html [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2593" >2010/05/20</a>, <a href="http://topsy.com/trackback?utm_source=pingback&amp;utm_campaign=L2&amp;url=http://www.laruence.com/2010/05/20/1495.html"  rel="external nofollow"  class="url" >Tweets that mention Nginx + PHP CGI的一个可能的安全漏洞 | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by blogkid, 姚东旭, lqik2004, fantasy, Laruence and others. Laruence said: 请转发, 这个漏洞的影响范围挺大:Nginx + PHP CGI的一个可能的安全漏洞 , http://www.laruence.com/2010/05/20/1495.html [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2594" >2010/05/20</a>, <a href="http://www.rddqi.com/"  rel="external nofollow"  class="url" >王经</a> writes: 好呀</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2595" >2010/05/20</a>, <a href="http://nod32.5151shop.com/?p=624"  rel="external nofollow"  class="url" >nod32升级id &raquo; nginx文件类型错误解析漏洞</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助 No tags for this [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2598" >2010/05/20</a>, <a href="http://jackywdx.cn/2010/05/path_info_in_php/"  rel="external nofollow"  class="url" >PHP中的PATH_INFO | 鸭嘴的blog</a> writes: [...] PHP中的PATH_INFO 2010-05-20 14:00:22 | PHP  一直没有理解$_SERVER[&#39;PATH_INFO&#39;]这个变量的意义，今天看了风雪之隅的一篇文章Nginx + PHP CGI的一个可能的安全漏洞之后才关注一下这个变量。 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2600" >2010/05/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 当当网发现此安全漏洞, 有谁认识当当的人么? 转发下, 让他们赶紧修复吧, 谢谢</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2602" >2010/05/21</a>, <a href="http://www.sgjblog.com/archives/55"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 | 失光 記。 | 当 雙眼 都失去光芒 你还想留念什么?|it新闻|it咨询|it博客门户|我们都在IT|软件资讯|绿色软件|失光软件</a> writes: [...] PS: 鸣谢laruence大牛在分析过程中给的帮助 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2603" >2010/05/21</a>, <a href="http://www.zoeey.com/"  rel="external nofollow"  class="url" >MoXie</a> writes: 这让我想起Apache中FilesMatch的漏洞。
FilesMatch "\.php"
结果造成文件名中只要包含.php就当Php执行了。
FilesMatch "\.php$" 这样才正确。</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2604" >2010/05/21</a>, <a href="http://scotoma.cnblogs.com"  rel="external nofollow"  class="url" >scotoma</a> writes: 谢谢...这个转发到Nginx群里面的了,提醒各位SA修改下配置文件,确实有很大的危害.
感谢博主</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2605" >2010/05/21</a>, <a href="http://icodex.org/2010/05/nginx%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b%e9%94%99%e8%af%af%e8%a7%a3%e6%9e%90%e6%bc%8f%e6%b4%9e/"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞</a> writes: [...]  或者  if ( $fastcgi_script_name ~ ..*/.*php ) { return 403; } PS: 鸣谢laruence大 牛在分析过程中给的帮助转载自: [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2606" >2010/05/21</a>, <a href="http://sanmuding.com"  rel="external nofollow"  class="url" >Anders</a> writes: 其实，从这个常见的 nginx 配置上看，是有问题的，最好还是严格一些的好。。

#      if ($uri ~ "^(\w+\.php)(/.*)") {
#           set $script $1;
#           set $path_info $2;
#      }</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2607" >2010/05/21</a>, <a href="http://www.xtgly.com/2010/05/21/nginx%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b%e9%94%99%e8%af%af%e8%a7%a3%e6%9e%90%e6%bc%8f%e6%b4%9e.htm"  rel="external nofollow"  class="url" >SystemAdmin Blog &raquo; Blog Archive &raquo; nginx文件类型错误解析漏洞</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2608" >2010/05/21</a>, <a href="http://www.vpser.net/manage/nginx-securit-script_filename.html"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 - VPS侦探</a> writes: [...]  或者  if ( $fastcgi_script_name ~ ..*/.*php ) { return 403; } PS: 鸣谢laruence大 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2609" >2010/05/21</a>, <a href="http://www.iamle.com/archives/602.html"  rel="external nofollow"  class="url" >nginx紧急漏洞修复！nginx文件类型错误解析漏洞 | 流水理鱼|wwek</a> writes: [...] PS: 鸣谢laruence大牛在分析过程中给的帮助 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2611" >2010/05/21</a>, <a href="http://blog.nekonokoya.cn/?p=150"  rel="external nofollow"  class="url" >猫の小屋 &raquo; Blog Archive &raquo; nginx文件类型错误解析漏洞</a> writes: [...] 鸣谢laruence大 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2612" >2010/05/21</a>, <a href="http://blog.zhoubing.org/10252.html"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 &laquo; zhoubing&#39;s blog</a> writes: [...] PS: 鸣谢laruence大牛在分析过程中给的帮助 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2613" >2010/05/21</a>, <a href="http://www.g78.net/index.php/nginx_securit"  rel="external nofollow"  class="url" >收藏一点 &raquo; nginx文件类型错误解析漏洞</a> writes: [...] PS: 鸣谢laruence大牛在分析过程中给的帮助 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2614" >2010/05/21</a>, <a href="http://blog.7xiaowu.cn/2010/05/21/1145.html"  rel="external nofollow"  class="url" >[转]nginx文件类型错误解析漏洞 | 游侠海外岛</a> writes: [...] 鸣谢laruence大 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2615" >2010/05/21</a>, <a href="http://www.shocr.com/nginx-securit-filetype/"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 - Blinux</a> writes: [...] jQuery(document).ready(function($){if(navigator.platform==&quot;iPad&quot;)return;jQuery(&quot;img&quot;).lazyload({effect:&quot;fadeIn&quot;,placeholder:&quot;http://www.shocr.com/wp-content/plugins/jquery-image-lazy-loading/images/grey.gif&quot;});});Blinux首页在线手册手机访问订阅RSS关于Englishnginx文件类型错误解析漏洞 Blinux Post in Linux的大杂烩，Tags: nginx, 安全 21 五月 2010 0 google_ad_client=&quot;pub-0521178536912504&quot;;google_ad_slot=&quot;8160586556&quot;;google_ad_width=468;google_ad_height=60; 热烈欢迎您来到Blinux!强烈推荐你订阅本博客 猛击此链接 .漏洞介绍：nginx是一款高性能的web服务器，使用非常广泛，其不仅经常被用作反向代理，也可以非常好的支持PHP的运行。80sec发现其中存在一个较为严重的安全问题，默认情况下可能导致服务器错误的将任何类型的文件以PHP的方式进行解析，这将导致严重的安全问题，使得恶意的攻击者可能攻陷支持php的nginx服务器。漏洞分析：nginx默认以cgi的方式支持php的运行，譬如在配置文件当中可以以location ~ .php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; include fastcgi_params; }的方式支持对php的解析，location对请求进行选择的时候会使用URI环境变量进行选择，其中传递到后端Fastcgi的关键变量SCRIPT_FILENAME由nginx生成的$fastcgi_script_name决定，而通过分析可以看到$fastcgi_script_name是直接由URI环境变量控制的，这里就是产生问题的点。而为了较好的支持PATH_INFO的提取，在PHP的配置选项里存在cgi.fix_pathinfo选项，其目的是为了从SCRIPT_FILENAME里取出真正的脚本名。 那么假设存在一个http://www.80sec.com/80sec.jpg，我们以如下的方式去访问http://www.80sec.com/80sec.jpg/80sec.php将会得到一个URI/80sec.jpg/80sec.php经过location指令，该请求将会交给后端的fastcgi处理，nginx为其设置环境变量SCRIPT_FILENAME，内容为/scripts/80sec.jpg/80sec.php而在其他的webserver如lighttpd当中，我们发现其中的SCRIPT_FILENAME被正确的设置为/scripts/80sec.jpg所以不存在此问题。 后端的fastcgi在接受到该选项时，会根据fix_pathinfo配置决定是否对SCRIPT_FILENAME进行额外的处理，一般情况下如果不对fix_pathinfo进行设置将影响使用PATH_INFO进行路由选择的应用，所以该选项一般配置开启。Php通过该选项之后将查找其中真正的脚本文件名字，查找的方式也是查看文件是否存在，这个时候将分离出SCRIPT_FILENAME和PATH_INFO分别为/scripts/80sec.jpg和80sec.php最后，以/scripts/80sec.jpg作为此次请求需要执行的脚本，攻击者就可以实现让nginx以php来解析任何类型的文件了。POC： 访问一个nginx来支持php的站点，在一个任何资源的文件如robots.txt后面加上/80sec.php，这个时候你可以看到如下的区别：访问http://www.80sec.com/robots.txtHTTP/1.1 200 OK Server: nginx/0.6.32 Date: Thu, 20 May 2010 10:05:30 GMT Content-Type: text/plain Content-Length: 18 Last-Modified: Thu, 20 May 2010 06:26:34 GMT Connection: keep-alive Keep-Alive: timeout=20 Accept-Ranges: bytes访问访问http://www.80sec.com/robots.txt/80sec.phpHTTP/1.1 200 OK Server: nginx/0.6.32 Date: Thu, 20 May 2010 10:06:49 GMT Content-Type: text/html Transfer-Encoding: chunked Connection: keep-alive Keep-Alive: timeout=20 X-Powered-By: PHP/5.2.6其中的Content-Type的变化说明了后端负责解析的变化，该站点就可能存在漏洞。漏洞厂商：http://www.nginx.org解决方案：我们已经尝试联系官方，但是此前你可以通过以下的方式来减少损失关闭cgi.fix_pathinfo为0或者if ( $fastcgi_script_name ~ ..*/.*php ) { return 403; }PS: 鸣谢laruence大牛在分析过程中给的帮助nginx文件类型错误解析漏洞:http://www.80sec.com/nginx-securit.html原创文章，转载请注明： 转载自Blinux本文链接地址: nginx文件类型错误解析漏洞No input file specified. (2)php安全设置之open_basedir (0)nginx windows发行已久 (0)nginx 301重定向 (4)给网站根目录添加sgid权限 (7)关闭Linux服务器ping响应 (0)nginx 自定义404 500 502 错误页面 (0)nginx 重启命令 (0)nginx 虚拟主机 (0) &laquo; Prev：SSH证书让Putty免密码登陆Linux Leave a Reply Name  Mail (will not be published)  Website [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2616" >2010/05/21</a>, <a href="http://blog.licess.org/nginx-securit-script_filename/"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 - Licess&#39;s Blog</a> writes: [...] 鸣谢laruence大 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2617" >2010/05/21</a>, <a href="http://www.vpslab.cn/104"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 @ VPS实验室</a> writes: [...] 鸣谢laruence大 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2618" >2010/05/21</a>, <a href="http://phprimer.com"  rel="external nofollow"  class="url" >Neaton</a> writes: 应该跟php-fpm的版本有关系，0.6以下除0.6以外的版本才受这个漏洞的影响，可以测试下。</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2619" >2010/05/21</a>, <a href="http://www.shusheng.tk/index.php/archives/83"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 - 书生博客</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助    上一篇:  帝国网站管理系统之自定义系统模型 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2620" >2010/05/21</a>, <a href="http://blog.guangla.com/nginx%e6%9a%b4%e5%ae%89%e5%85%a8%e6%bc%8f%e6%b4%9e%ef%bc%8c%e5%af%bc%e8%87%b4%e6%9c%8d%e5%8a%a1%e5%99%a8%e8%a2%ab%e6%8f%90%e6%9d%83/"  rel="external nofollow"  class="url" >Nginx暴安全漏洞，导致服务器被提权</a> writes: [...] 鸣谢laruence大 牛在分析过程中给的帮助    &nbsp;     0 评论   Leave A [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2621" >2010/05/21</a>, <a href="http://www.mmyuqi.com"  rel="external nofollow"  class="url" >两性解答</a> writes: <a href="http://www.mmyuqi.com/"  rel="nofollow" >两性解答</a>关注一下</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2623" >2010/05/21</a>, <a href="http://key0.cn/index.php/archives/730"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 &#8211; kindle&#39;s blog</a> writes: [...] 鸣谢laruence大 牛在分析过程中给的帮助    Posted on 2010-05-21 at 3:05 下午 | Filed: 网络文摘 | [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2624" >2010/05/21</a>, <a href="http://www.shotki.com/hezll/2010/05/nginxphp-80sec-0day%e6%bc%8f%e6%b4%9e%e8%af%a6%e7%bb%86%e5%88%86%e6%9e%90%ef%bc%9afix_pathinfo/"  rel="external nofollow"  class="url" >Nginx/PHP 80sec 0day漏洞详细分析：fix_pathinfo &laquo; Hezll 博客</a> writes: [...] http://www.laruence.com/2010/05/20/1495.html [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2628" >2010/05/21</a>, Bingo writes: http://wiki.nginx.org/NginxHttpFcgiModule#fastcgi_split_path_info

图片上传的路径加上这个配置可能就可以了
location ~ ^(.+\.jpe?g)(.*)$ {
...
fastcgi_split_path_info ^(.+\.jpe?g)(.*)$;
fastcgi_param SCRIPT_FILENAME /path/to/php$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
...
}</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2630" >2010/05/21</a>, <a href="http://aggron.org/archives/nginx-fcgi-php-scriptname-bug.html"  rel="external nofollow"  class="url" >Aggron的博客 &raquo; nginx php cgi漏洞</a> writes: [...] 从http://www.laruence.com/2010/05/20/1495.html看到的：nginx+fcgi+php可能会存在一个很严重的安全漏洞。使用nginx + fcgi跑PHP的童鞋注意了，据说已经有网站中招。 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2632" >2010/05/21</a>, <a href="http://www.0xf3sec.org/nginx%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b%e9%94%99%e8%af%af%e8%a7%a3%e6%9e%90%e6%bc%8f%e6%b4%9e/"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 | 0xf3sec&#39;blog</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助  [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2633" >2010/05/21</a>, <a href="http://www.akang.info/?p=462"  rel="external nofollow"  class="url" >IIS漏洞和nginx漏洞同时爆出，你的网站被爆了吗？ - 阿伉守候</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助  [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2635" >2010/05/22</a>, <a href="http://www.ershao.net/archives/280.html"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 - 二少&#39;s Blog</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助 评论（0） [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2636" >2010/05/22</a>, <a href="http://www.miao.la/2010/05/nginx-exp-and-%e6%bc%8f%e6%b4%9e%e6%89%ab%e6%8f%8f%e5%99%a8/"  rel="external nofollow"  class="url" >MIAO&#39;BLOG &raquo; Blog Archive &raquo; nginx exp and 漏洞扫描器</a> writes: [...] 延伸阅读：laruence [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2637" >2010/05/22</a>, <a href="http://www.linuxzj.com/nginx/nginx-securit.html"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 | Linux之家</a> writes: [...] PS: 鸣谢laruence大牛在分析过程中给的帮助 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2638" >2010/05/22</a>, <a href="http://www.phpvim.net/php/security-risks-caused-by-fix-pathinfo.html"  rel="external nofollow"  class="url" >Verdana DevNotes &raquo; PHP CGI 中 fix_pathinfo 引起的安全隐患</a> writes: [...] 关于这个问题，已有高手 laruence 做过详细的分析，这里再多啰嗦几句。 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2639" >2010/05/23</a>, <a href="http://www.xslife.net/?p=313"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞&#8211;（转） | 品味人生，享受生活</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助   转自：80sec.com [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2640" >2010/05/23</a>, <a href="http://www.xxc.com"  rel="external nofollow"  class="url" >Free</a> writes: This is ......(T)</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2642" >2010/05/23</a>, <a href="http://blog.sudu.us/linux/nginx-securit-script.html"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 | Sudu&#39;s Blog</a> writes: [...] ( $fastcgi_script_name ~ ..*/.*php ) { return 403; }  PS: 鸣谢laruence大 牛在分析过程中给的帮助转载自：http://www.80sec.com/nginx-securit.html日志信息 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2643" >2010/05/24</a>, <a href="http://www.js4j.com"  rel="external nofollow"  class="url" >技术门户网站</a> writes: 好专业，不过很久没更新啦</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2644" >2010/05/24</a>, <a href="http://www.joey.ws/%e5%b9%bf%e8%80%8c%e5%91%8a%e4%b9%8b/nginx%e5%8f%91%e7%8e%b0%e9%87%8d%e5%a4%a7%e6%bc%8f%e6%b4%9e/"  rel="external nofollow"  class="url" >Nginx发现重大漏洞 | 袋鼠空间 - Just One Eximious Yelling! 超凡者的呐喊！</a> writes: [...] 鸣谢laruence大 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2645" >2010/05/24</a>, <a href="http://blog.unicoicn.com/2010/05/nginx%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b%e9%94%99%e8%af%af%e8%a7%a3%e6%9e%90%e6%bc%8f%e6%b4%9e.html"  rel="external nofollow"  class="url" >乾亨网络工作室 &raquo; Blog Archive &raquo; nginx文件类型错误解析漏洞</a> writes: [...]  或者  if ( $fastcgi_script_name ~ ..*/.*php ) { return 403; } PS: 鸣谢laruence大牛在分析过程中给的帮助No related posts.以上关联文章由 Yet Another Related Posts [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2649" >2010/05/24</a>, <a href="http://www.xujun.org/?p=156"  rel="external nofollow"  class="url" >junjun的世界 &raquo; nginx文件类型错误解析漏洞</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助    发表评论 | Trackback        [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2674" >2010/05/26</a>, <a href="http://www.afeiblog.com.cn/index.php/archives/281"  rel="external nofollow"  class="url" >阿飞的博客 &raquo; nginx文件类型错误解析漏洞</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2697" >2010/05/31</a>, <a href="http://www.07mi.com/vps-optimization-setup/nginx-oday-80sec/"  rel="external nofollow"  class="url" >齐米优惠吧 &raquo; Blog Archive &raquo; nginx文件类型错误解析漏洞</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助  转载自：http://www.80sec.com/nginx-securit.html    Don&#39;t [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2700" >2010/06/01</a>, <a href="http://www.imiyoo.com/blog/?p=19"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 | i-Mi-Yoo</a> writes: [...] PS: 鸣谢laruence大牛在分析过程中给的帮助 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2721" >2010/06/09</a>, <a href="http://oblog.weilaijieshi.com/?p=10"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 &laquo; 莫忘雪</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助  评论（0） [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2727" >2010/06/09</a>, <a href="http://www.phpiis.com/archives/27"  rel="external nofollow"  class="url" >PHPiis-坏孩子的天空 &raquo; Blog Archive &raquo; nginx文件类型错误解析漏洞</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助  [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2729" >2010/06/10</a>, <a href="http://www.dt1x.com"  rel="external nofollow"  class="url" >打听1下</a> writes: 很严重的安全漏洞。</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2769" >2010/06/21</a>, <a href="http://www.bander.com.cn"  rel="external nofollow"  class="url" >Bander</a> writes: 弱弱问一句：关闭cgi.fix_pathinfo为0 可否解决噢？</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2974" >2010/07/23</a>, <a href="http://faker.iblogger.org/2010/07/nginx%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b%e9%94%99%e8%af%af%e8%a7%a3%e6%9e%90%e6%bc%8f%e6%b4%9e/"  rel="external nofollow"  class="url" >nginx文件类型错误解析漏洞 | 会跳舞的鞋子</a> writes: [...] 鸣谢laruence大牛在分析过程中给的帮助       这篇日志发表于 Jul 22nd, 2010 08:31 于分类 [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-2992" >2010/07/27</a>, <a href="http://www.bestfinance-blog.com"  rel="external nofollow"  class="url" >SerranoMaritza33</a> writes: Following my own exploration, thousands of persons on our planet receive the <a href="http://bestfinance-blog.com/topics/personal-loans"  rel="nofollow" >personal loans</a> from good banks. Therefore, there's great possibilities to receive a car loan in all countries.</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-3064" >2010/08/06</a>, <a href="http://www.lampblog.cn/?p=33"  rel="external nofollow"  class="url" >Trail&#39;s Blog &raquo; Nginx(PHP/fastcgi)的PATH_INFO问题</a> writes: [...] 最近发现的一个安全漏洞(Nginx + PHP CGI的一个可能的安全漏洞)和这个配置有关系, 请大家务必在使用第二种配置的时候,关闭cgi.fix_pathinfo. [...]</li><li><a href="http://www.laruence.com/2010/05/20/1495.html#comment-3168" >2010/09/07</a>, Anonymous writes: if ($request_filename ~* (.*)\\.php) {
                 set $php_url $1;
             }
             if (!-e $php_url.php) {
                 return 403;
             }





blog:blog.sina.com.cn/harleychen</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/05/20/1495.html/feed</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>深入理解PHP原理之对象(一)</title>
		<link>http://www.laruence.com/2010/05/18/1482.html</link>
		<comments>http://www.laruence.com/2010/05/18/1482.html#comments</comments>
		<pubDate>Tue, 18 May 2010 05:10:45 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[object]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php源码分析]]></category>
		<category><![CDATA[原理]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1482</guid>
		<description><![CDATA[<p>
	在PHP4以前, PHP并不支持面向对象, 到PHP4的时候, PHP引入了一些OOP的关键字, 请注意我用的"关键字", 因为在PHP4中的对象, 不过就是一个数组(属性)加上一个函数数组(方法), 没有访问权限控制, 没有析构函数(当然可以<a href="http://www.laruence.com/2008/09/04/498.html">模拟</a>), 等等.

	到PHP5以后, 随着Zend Engine 2的发布:
<coolcode lang="bash" lienum="off">
1. 访问权限控制
2. 接口的引入
3. 魔术方法(PHP4中可以通过overload来有限模拟) 
4. 接口的应用
5. 内置接口
等等.
</coolcode>
    PHP5终于可以算是较完美的支持面向对象了.

    而这些看似复杂的实现, 在根本上, 还是没有脱离属性数组+方法数组的基本, 接下来我就为大家揭开隐藏在源代码中的秘密.]]></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/05/18/1482.html"  title="Permanet Link to 深入理解PHP原理之对象(一)" >http://www.laruence.com/2010/05/18/1482.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	在PHP4以前, PHP并不支持面向对象, 到PHP4的时候, PHP引入了一些OOP的关键字, 请注意我用的&#8221;关键字&#8221;, 因为在PHP4中的对象, 不过就是一个数组(属性)加上一个函数数组(方法), 没有访问权限控制, 没有析构函数(当然可以<a href="http://www.laruence.com/2008/09/04/498.html" >模拟</a>), 等等.</p>
<p>	到PHP5以后, 随着Zend Engine 2的发布:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. 访问权限控制
2. 接口的引入
3. 魔术方法(PHP4中可以通过overload来有限模拟)
4. 接口的应用
5. 内置接口
等等.
</pre>
<p>    PHP5终于可以算是较完美的支持面向对象了.</p>
<p>    而这些看似复杂的实现, 在根本上, 还是没有脱离属性数组+方法数组的基本, 接下来我就为大家揭开隐藏在源代码中的秘密.</p>
<p>   <b>对象的结构</b></p>
<p>   在PHP5中, 一个对象, 还是以一个zval做为载体的, 还记得什么是Zval么(<a href="http://www.laruence.com/2008/08/22/412.html"  target="_blank" >深入理解PHP原理之变量</a>).</p>
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
typedef union _zvalue_value {
    long lval;
    double dval;
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;
    zend_object_value obj;
} zvalue_value;
</pre>
<p>	如果, 一个zval是对象, 那么zvalue_value中的obj, 就指向一个zend_object_value的实例.</p>
<p>	一个zend_object_value包含俩个成员, 一个是标识符(整形序号), 表明了当前对象存储在全局对象列表的位置, 另外还有一个zend_object_handlers指针, 指向当前对象所属类的handlers(标准操作集合).</p>
<p>	真正的对象实体, zend_object中, 保存了如下的关键信息入口:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. ce, zend_class_entry 类入口
2. properties, hashTable 普通属性集
</pre>
<p>   <b>对象的属性</b></p>
<p>	如上所述, 普通属性是一个的hashTable, 在PHP5以后, 引入了访问权限控制, 而访问权限属性, 是通过属性名进行区分的(为此Zend引入了zend_mangle_property_name).</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. public  属性名
2. private \0类名\0属性名
3. protected \0*\0属性名
</pre>
<p>	PHP通过这种比较ugly但是简单高效的方法, 实现了对属性访问权限的标识.知道了这个, 我们就可以干一些不合常理的事请, 比如访问对象的私有/保护属性(见: <a href="http://bugs.php.net/bug.php?id=44273"  target="_blank" >Bug #44273	access to private and protected class variables allowed when casting to array</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;">
class Foo {
    private $_name = &quot;laruence&quot;;
    protected $_age = 28;
}
$foo = new Foo();
$arr = (array) $foo;
var_dump($arr[&quot;\0Foo\0_name&quot;]);
var_dump($arr[&quot;\0*\0_age&quot;]);
//output:
string(8) &quot;laruence&quot;
int(28)
</pre>
<p>    既然我说到了普通属性, 那么也就有不普通的属性:Static/Constant, 因为静态属性和常量属性都是和类相关而不是和对象相关的, 那么想到然的, 这些属性也就应该保存在类的结构中, 也就是zend_class_entry中. 对象的方法同理也是和类绑定的.</p>
<p>	在zend_class_entry, 有如下HashTable几个成员,</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. function_table, 方法集
2. default_static_members, 静态属性
3. default_properties, 默认的属性
4. constants_table, 常量表
</pre>
<p>	属性如其名, 对象类型的属性, 存放在对象的成员中.</p>
<p>   <b>对象的方法</b></p>
<p>	在zend_class_entry中的function_table是个hashTable, 这个函数表的结构和普通的函数表一样(<a href="http://www.laruence.com/2008/08/12/164.html"  target="_blank" >深入理解PHP之函数</a>), 也是以zend_op_array为最终载体, 所以和普通函数一样, 方法也是不区分大小写的, 也是可以附加arg_info的. 而不同的则是, 函数的访问权限则由zend_op_array的fn_flag属性表明.</p>
<p>	我们知道, 在PHP内的函数, 都有统一的参数列表(遵守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;">
#define INTERNAL_FUNCTION_PARAM_PASSTHRU ht, return_value, return_value_ptr, this_ptr, return_value_used TSRMLS_CC
</pre>
<p>   在调用方法的时候, this关键字由函数参数中的this_ptr指明,  而对于用户定义的函数, this关键字则有Zend VM保证.</p>
<p>   说到这里, 举个列子:</p>
<p>   如下代码, 会得到Fatal</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
class Foo {
   public function Say() {
      $this = NULL;
   }
}
?&gt;
//output:
PHP Fatal error:  Cannot re-assign $this in **
</pre>
<p>   这是一个初级的保护措施, 防止this关键字被改写, 难道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
class Foo {
    public $id  = &quot;laruence&quot;;
    function Say($arr) {
        extract($arr, EXTR_OVERWRITE);
        var_dump($this);
        var_dump($this-&gt;id);
    }
}
$a = new Foo(); 

$a-&gt;sAY(array(&quot;this&quot; =&gt; NULL)); //只是未来说明方法名不区分大小写.
?&gt;
//output:
NULL
string(8) &quot;laruence&quot;
</pre>
<p>	可见this关键字, 并不是简单的符号表中的item. 是在语法分析阶段, 就由ZEND Engine保证其正确性的, 并Attach在函数的结构体中.</p>
<p>   <b>对象的标准操作</b><br/>
    我们对对象的操作, 比如获取属性, 设置属性, 获取对象的类, 等等, 这些常用的方法, 都是实现在对象的标准方法中的,PHP5中, 提供了23个标准方法.</p>
<p>	在zend_object_value中的handlers指针, 就指向类常用操作的方法集合, 默认的, 这个指针指向:</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 zend_object_handlers std_object_handlers = {
    zend_objects_store_add_ref,             /* add_ref */
    zend_objects_store_del_ref,             /* del_ref */
    zend_objects_clone_obj,                 /* clone_obj */

    zend_std_read_property,                 /* read_property */
    zend_std_write_property,                /* write_property */
    zend_std_read_dimension,                /* read_dimension */
    zend_std_write_dimension,               /* write_dimension */
    zend_std_get_property_ptr_ptr,          /* get_property_ptr_ptr */
    NULL,                                   /* get */
    NULL,                                   /* set */
    zend_std_has_property,                  /* has_property */
    zend_std_unset_property,                /* unset_property */
    zend_std_has_dimension,                 /* has_dimension */
    zend_std_unset_dimension,               /* unset_dimension */
    zend_std_get_properties,                /* get_properties */
    zend_std_get_method,                    /* get_method */
    NULL,                                   /* call_method */
    zend_std_get_constructor,               /* get_constructor */
    zend_std_object_get_class,              /* get_class_entry */
    zend_std_object_get_class_name,         /* get_class_name */
    zend_std_compare_objects,               /* compare_objects */
    zend_std_cast_object_tostring,          /* cast_object */
    NULL,                                   /* count_elements */
};
</pre>
<p>	默认的, 也是绝大多数的时候, 都是如上的这些标准方法.</p>
<p>	需要指明的是, _dimension后缀的方法, 指的是通过数组($obj['name'])方式访问对象的属性.</p>
<p><b>魔术方法</b></p>
<p>	魔术方法定义在class_entry中, </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;">
union _zend_function *constructor;
union _zend_function *destructor;
union _zend_function *clone;
union _zend_function *__get;
union _zend_function *__set;
union _zend_function *__unset;
union _zend_function *__isset;
union _zend_function *__call;
union _zend_function *__tostring;
union _zend_function *serialize_func;
union _zend_function *unserialize_func;
</pre>
<p>	魔术方法没有默认值, 在类定义的时刻指定.</p>
<p>	对于一些魔术方法, 比如__get/__set是被标准操作发起调用的, 所以如果我们自己编写扩展中定义的类, 如果不使用标准方法, 那么也需要在适当的时机, 主动调用这些魔术方法.
</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_c.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><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_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_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/2010/05/18/1482.html#comment-2582" >2010/05/18</a>, <a href="http://topsy.com/trackback?utm_source=pingback&amp;utm_campaign=L1&amp;url=http://www.laruence.com/2010/05/18/1482.html"  rel="external nofollow"  class="url" >Tweets that mention 深入理解PHP原理之对象(一) | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by 姚东旭. 姚东旭 said: [推荐] 深入理解PHP原理之对象(一) http://goo.gl/gUMh [...]</li><li><a href="http://www.laruence.com/2010/05/18/1482.html#comment-2591" >2010/05/20</a>, <a href="http://www.phppan.com"  rel="external nofollow"  class="url" >phppan</a> writes: 之前由于一个纠结的私有变量的问题而看过php中类实现的一些代码，但也是粗略了解，
今天拜读鸟哥的文章，再次学习了！</li><li><a href="http://www.laruence.com/2010/05/18/1482.html#comment-2622" >2010/05/21</a>, <a href="http://www.xingai114.com"  rel="external nofollow"  class="url" >xingai</a> writes: <a href="http://www.xingai114.com"  rel="nofollow" >xingai</a>再次学习了！</li><li><a href="http://www.laruence.com/2010/05/18/1482.html#comment-2661" >2010/05/26</a>, <a href="http://crazyphper.com/wblog/archives/777"  rel="external nofollow"  class="url" >深入理解 PHP之require/include顺序 &laquo; 大熊猫 &#8211; konakona ——PHP程序员</a> writes: [...] 本文地址: http://www.laruence.com/2010/05/18/1482.html [...]</li><li><a href="http://www.laruence.com/2010/05/18/1482.html#comment-2760" >2010/06/18</a>, abcasus 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/05/18/1482.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>使用PHP_UML生成代码的UML图</title>
		<link>http://www.laruence.com/2010/05/14/1473.html</link>
		<comments>http://www.laruence.com/2010/05/14/1473.html#comments</comments>
		<pubDate>Fri, 14 May 2010 07:38:01 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[随笔]]></category>
		<category><![CDATA[mapforce]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php_uml]]></category>
		<category><![CDATA[xmi]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1473</guid>
		<description><![CDATA[在读别人代码的时候, 在没有详细文档的时候, 如何快速的看清整个代码的结构(类结构), 就成为了一个现实的问题.

    今天我就介绍一种, 自动生成UML图的方法.]]></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/05/14/1473.html"  title="Permanet Link to 使用PHP_UML生成代码的UML图" >http://www.laruence.com/2010/05/14/1473.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
    在读别人代码的时候, 在没有详细文档的时候, 如何快速的看清整个代码的结构(类结构), 就成为了一个现实的问题.</p>
<p>    今天我就介绍一种, 自动生成UML图的方法.</p>
<p>    假设, 我有一个项目文件夹:laruence, 在这个文件夹上有一个文件Root.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

abstract class Root {
    private $instance;
    abstract public function Hi();
}

interface Intro {
    public function Say();
}

class Sub extends Root implements Intro {
    private $instance;
    public function Say() {
        echo &quot;I am Laruence&quot;;
    }
    public function Hi() {
        echo &quot;Hello!&quot;;
    }
}
?&gt;
</pre>
<p>    首先, 我们要使用PHP_UML(<a href="http://pear.php.net/package/PHP_UML"  target="_blank" >PHP_UML</a>)根据代码生成XMI.</p>
<p>    使用方法比较简单, 在安装PHP_UML以后, 运行:</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;">
 phpuml laruence/ -o laruence.xmi -n laruence -f xmi  --pure-object --no-deployment-view  --no-component-view --no-docblocks
</pre>
<p>   会得到一个laruence.xmi文件, phpuml的具体参数可以通过phpuml &#8211;help了解.</p>
<p>   有了xmi以后, 如何转成UML图呢?</p>
<p>   Visio2007不支持导入XMI, 我找到了另外的一个工具:<a href="http://www.altova.com/umodel.html"  target="_blank" >Altova Umodel</a>, 这个工具可以支持XMI到UML图的转换, 需要注册, 不过提供了30天的使用许可(大家要是有更好的替换方案, 欢迎补充).</p>
<p>   在Umodel导入laruence.xmi以后 ,生成UML图, 就得到了如下的PNG:</p>
<div id="attachment_1476"  class="wp-caption aligncenter"  style="width: 570px" ><a href="http://www.laruence.com/wp-content/uploads/laruence1.png" ><img src="http://www.laruence.com/wp-content/uploads/laruence1.png"  alt="UML图"  title="laruence"  width="560"  height="445"  class="size-full wp-image-1476" /></a><p class="wp-caption-text" >UML图</p></div>
<p>   是不是很方便呢?</p>
<p>   另外PHP_UML还可以生成html格式, 做为一种doc gen工具也不错. 更可以通过xmi生成PHP文件.<br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2568" >2010/05/14</a>, <a href="http://54chen.com"  rel="external nofollow"  class="url" >cc0cc</a> writes: 哥学社不遗余力地顶起，有没有反向的办法，通过uml生成php代码？</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2569" >2010/05/14</a>, toms writes: 要是能进一步识别程序的调用关系就更好啦</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2570" >2010/05/14</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @cc0cc 有, visio 03据说有个插件, 可以把UML图导出成XMI. PHP_UML就可以根据XMI生成PHP代码了, 当然, mapForce也可以导出XMI</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2571" >2010/05/14</a>, <a href="http://topsy.com/trackback?utm_source=pingback&amp;utm_campaign=L1&amp;url=http://www.laruence.com/2010/05/14/1473.html"  rel="external nofollow"  class="url" >Tweets that mention 使用PHP_UML生成代码的UML图 | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by 小白. 小白 said: 使用PHP_UML生成代码的UML图 - http://goo.gl/UAQp [...]</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2580" >2010/05/18</a>, 玉丰 writes: 哈哈，去试试。还有，建议换个验证码，现在这个太难用了。</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2641" >2010/05/23</a>, <a href="http://www.jaceju.net/blog/?p=1175"  rel="external nofollow"  class="url" >網站製作學習誌 &raquo; [Web] 連結分享</a> writes: [...] 使用PHP_UML生成代码的UML图 [...]</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2704" >2010/06/05</a>, luckgo writes: 我折腾到深夜，装了Altova MapForce,但怎么也找不到导入xmi的菜单，倒是在google上找到Altova Umodel导入xmi的介绍，请问Laruence，是不是你搞错了耶？</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2705" >2010/06/05</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @luckgo  正是, 正是, 多谢指正, 已经修改.</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-2943" >2010/07/16</a>, <a href="http://dothing"  rel="external nofollow"  class="url" >lake</a> writes: 好东西，谢谢，今晚有得折腾了。哈哈</li><li><a href="http://www.laruence.com/2010/05/14/1473.html#comment-3080" >2010/08/11</a>, tirisfal writes: 如果是导出html，怎么支持utf-8呢？</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/05/14/1473.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>深入理解ob_flush和flush的区别</title>
		<link>http://www.laruence.com/2010/04/15/1414.html</link>
		<comments>http://www.laruence.com/2010/04/15/1414.html#comments</comments>
		<pubDate>Thu, 15 Apr 2010 03:41:52 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[flush]]></category>
		<category><![CDATA[ob_flush]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1414</guid>
		<description><![CDATA[ ob_flush/flush在手册中的描述, 都是刷新输出缓冲区, 并且还需要配套使用, 所以会导致很多人迷惑...

   其实, 他们俩的操作对象不同, 有些情况下, flush根本不做什么事情..]]></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/04/15/1414.html"  title="Permanet Link to 深入理解ob_flush和flush的区别" >http://www.laruence.com/2010/04/15/1414.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   ob_flush/flush在手册中的描述, 都是刷新输出缓冲区, 并且还需要配套使用, 所以会导致很多人迷惑&#8230;</p>
<p>   其实, 他们俩的操作对象不同, 有些情况下, flush根本不做什么事情..</p>
<p>   ob_*系列函数, 是操作PHP本身的输出缓冲区. </p>
<p>   所以, ob_flush是刷新PHP自身的缓冲区.</p>
<p>   而flush, 严格来讲, 这个只有在PHP做为apache的Module(handler或者filter)安装的时候, 才有实际作用.  它是刷新WebServer(可以认为特指apache)的缓冲区.</p>
<p>   在apache module的sapi下, flush会通过调用sapi_module的flush成员函数指针, 间接的调用apache的api: ap_rflush刷新apache的输出缓冲区, 当然手册中也说了, 有一些apache的其他模块, 可能会改变这个动作的结果..</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;">
有些Apache的模块，比如mod_gzip，可能自己进行输出缓存，
这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。 

甚至浏览器也会在显示之前，缓存接收到的内容。例如 Netscape
浏览器会在接受到换行或 html 标记的开头之前缓存内容，并且在
接受到 &lt;/table&gt; 标记之前，不会显示出整个表格。 

一些版本的 Microsoft Internet Explorer 只有当接受到的256个
字节以后才开始显示该页面，所以必须发送一些额外的空格来让这
些浏览器显示页面内容。
</pre>
<p>   所以, 正确使用俩者的顺序是. 先ob_flush, 然后flush,</p>
<p>   当然, 在其他sapi下, 不调用flush也可以, 只不过为了保证你代码的可移植性, 建议配套使用.
</p>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/04/15/1414.html#comment-2512" >2010/04/16</a>, <a href="http://ziranxi.com"  rel="external nofollow"  class="url" >Anonymous</a> writes: 很好，尤其在comet等需要特别注意cache的场景，需要注意这些</li><li><a href="http://www.laruence.com/2010/04/15/1414.html#comment-2513" >2010/04/16</a>, <a href="http://topsy.com/trackback?utm_source=pingback&amp;utm_campaign=L1&amp;url=http://www.laruence.com/2010/04/15/1414.html"  rel="external nofollow"  class="url" >Tweets that mention 深入理解ob_flush和flush的区别 | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by Angus Li. Angus Li said: 深入理解ob_flush和flush的区别 http://ff.im/-j5oDz [...]</li><li><a href="http://www.laruence.com/2010/04/15/1414.html#comment-2515" >2010/04/17</a>, <a href="http://www.jaceju.net/blog/?p=1108"  rel="external nofollow"  class="url" >網站製作學習誌 &raquo; [Web] 連結分享</a> writes: [...] 深入理解ob_flush和flush的區別 [...]</li><li><a href="http://www.laruence.com/2010/04/15/1414.html#comment-2516" >2010/04/17</a>, <a href="http://www.lacorey.com"  rel="external nofollow"  class="url" >xiaokai</a> writes: 受教了, 能否加个友情链接. http://www.lacorey.com 贵站的已加了..</li><li><a href="http://www.laruence.com/2010/04/15/1414.html#comment-2583" >2010/05/19</a>, Sun writes: 谢谢</li><li><a href="http://www.laruence.com/2010/04/15/1414.html#comment-3169" >2010/09/07</a>, <a href="http://www.bestfinance-blog.com"  rel="external nofollow"  class="url" >Lela22Stein</a> writes: Every body remembers that our life is not cheap, nevertheless some people need cash for different stuff and not every one gets enough cash. Therefore to get fast <a href="http://bestfinance-blog.com/topics/mortgage-loans"  rel="nofollow" >mortgage loans</a> and bank loan should be good way out.</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/04/15/1414.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>深入理解SET NAMES和mysql(i)_set_charset的区别</title>
		<link>http://www.laruence.com/2010/04/12/1396.html</link>
		<comments>http://www.laruence.com/2010/04/12/1396.html#comments</comments>
		<pubDate>Mon, 12 Apr 2010 14:10:27 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[MySQL/PostgreSQL]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[mysqli:set_charset]]></category>
		<category><![CDATA[mysqli_set_charset]]></category>
		<category><![CDATA[mysql_set_charset]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[set names]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1396</guid>
		<description><![CDATA[最近公司组织了个PHP安全编程的培训, 其中涉及到一部分关于Mysql的"SET NAMES"和mysql_set_charset (mysqli_set_charset)的内容:
  
  说到, 尽量使用mysqli_set_charset而不是"SET NAMES", 当然, 这个内容在PHP手册中也有叙及, 但是却没有解释为什么.

  最近有好几个朋友问我这个问题, 到底为什么?

  问的人多了, 我也就觉得可以写篇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/04/12/1396.html"  title="Permanet Link to 深入理解SET NAMES和mysql(i)_set_charset的区别" >http://www.laruence.com/2010/04/12/1396.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
  最近公司组织了个PHP安全编程的培训, 其中涉及到一部分关于Mysql的&#8221;SET NAMES&#8221;和mysql_set_charset (mysqli_set_charset)的内容:</p>
<p>  说到, 尽量使用mysqli_set_charset(mysqli:set_charset)而不是&#8221;SET NAMES&#8221;, 当然, 这个内容在PHP手册中也有叙及, 但是却没有解释为什么.</p>
<p>  最近有好几个朋友问我这个问题, 到底为什么?</p>
<p>  问的人多了, 我也就觉得可以写篇blog, 专门介绍下这部分的内容了.</p>
<p>  首先, 很多人都不知道&#8221;SET NAMES&#8221;到底是做了什么,</p>
<p>  我之前的文章<a href="http://www.laruence.com/2008/01/05/12.html" >深入MySQL字符集设置</a>中, 曾经介绍过character_set_client/character_set_connection/character_set_results这三个MySQL的&#8221;环境变量&#8221;,  这里再简单介绍下,</p>
<p>  这三个变量, 分别告诉MySQL服务器, 客户端的编码集, 在传输给MySQL服务器的时候的编码集, 以及期望MySQL返回的结果的编码集.</p>
<p>  比如, 通过使用&#8221;SET NAMES utf8&#8243;, 就告诉服务器, 我用的是utf-8编码, 我希望你也给我返回utf-8编码的查询结果.</p>
<p>  一般情况下, 使用&#8221;SET NAMES&#8221;就足够了, 也是可以保证正确的. 那么为什么手册又要说推荐使用mysqli_set_charset(PHP>=5.0.5)呢?</p>
<p>  首先, 我们看看mysqli_set_charset到底做了什么(注意星号注释处, mysql_set_charset类似):</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;">
//php-5.2.11-SRC/ext/mysqli/mysqli_nonapi.c line 342
PHP_FUNCTION(mysqli_set_charset)
{
    MY_MYSQL            *mysql;
    zval                *mysql_link;
    char                *cs_name = NULL;
    unsigned int        len;

    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis()
		, &quot;Os&quot;, &amp;mysql_link, mysqli_link_class_entry, &amp;cs_name, &amp;len) == FAILURE) {
        return;
    }
    MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL*, &amp;mysql_link, &quot;mysqli_link&quot;
        , MYSQLI_STATUS_VALID);

    if (mysql_set_character_set(mysql-&gt;mysql, cs_name)) {
		//** 调用libmysql的对应函数
        RETURN_FALSE;
    }
    RETURN_TRUE;
}
</pre>
<p>  那mysql_set_character_set又做了什么呢?</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;">
//mysql-5.1.30-SRC/libmysql/client.c, line 3166:
int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
{
  struct charset_info_st *cs;
  const char *save_csdir= charsets_dir;

  if (mysql-&gt;options.charset_dir)
    charsets_dir= mysql-&gt;options.charset_dir;

  if (strlen(cs_name) &lt; MY_CS_NAME_SIZE &amp;&amp;
     (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
  {
    char buff[MY_CS_NAME_SIZE + 10];
    charsets_dir= save_csdir;
    /* Skip execution of &quot;SET NAMES&quot; for pre-4.1 servers */
    if (mysql_get_server_version(mysql) &lt; 40100)
      return 0;
    sprintf(buff, &quot;SET NAMES %s&quot;, cs_name);
    if (!mysql_real_query(mysql, buff, strlen(buff)))
    {
      mysql-&gt;charset= cs;
    }
  }
  //以下省略
</pre>
<p>  我们可以看到, mysqli_set_charset除了做了&#8221;SET NAMES&#8221;以外, 还多做了一步:</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;">
sprintf(buff, &quot;SET NAMES %s&quot;, cs_name);
if (!mysql_real_query(mysql, buff, strlen(buff)))
{
  mysql-&gt;charset= cs;
}
</pre>
<p>  而对于mysql这个核心结构的成员charset又有什么作用呢?</p>
<p>  这就要说说mysql_real_escape_string()了, 这个函数和mysql_escape_string的区别就是, 它会考虑&#8221;当前&#8221;字符集. 那么这个当前字符集从哪里来呢?</p>
<p>  对了, 你猜的没错, 就是mysql->charset.</p>
<p>  mysql_real_string在判断宽字符集的字符的时候, 就根据这个成员变量来分别采用不同的策略, 比如如果是utf-8, 那么就会采用libmysql/ctype-utf8.c.</p>
<p>  看个实例, 默认mysql连接字符集是latin-1, (经典的5c问题):</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
    $db = mysql_connect('localhost:3737', 'root' ,'123456');
    mysql_select_db(&quot;test&quot;);
    $a = &quot;\x91\x5c&quot;;//&quot;慭&quot;的gbk编码, 低字节为5c, 也就是ascii中的&quot;\&quot;

    var_dump(addslashes($a));
    var_dump(mysql_real_escape_string($a, $db));

    mysql_query(&quot;set names gbk&quot;);
    var_dump(mysql_real_escape_string($a, $db));

    mysql_set_charset(&quot;gbk&quot;);
    var_dump(mysql_real_escape_string($a, $db));
?&gt;
</pre>
<p>因为, &#8220;慭&#8221;的gbk编码低字节为5c, 也就是ascii中的&#8221;\&#8221;, 而因为除了mysql(i)_set_charset影响mysql->charset以外, 其他时刻mysql->charset都为默认值, 所以, 结果就是:</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 -f 5c.php
string(3) &quot;慭\&quot;
string(3) &quot;慭\&quot;
string(3) &quot;慭\&quot;
string(2) &quot;慭&quot;
</pre>
<p>  大家现在很清楚了吧?
</p>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_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_bash.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2498" >2010/04/12</a>, qywyh writes: 看贴不回木jj，学习了,顶！</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2500" >2010/04/12</a>, <a href="http://www.felix021.com"  rel="external nofollow"  class="url" >felix021</a> writes: 1L真狠。。。</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2501" >2010/04/13</a>, <a href="http://topsy.com/trackback?utm_source=pingback&amp;utm_campaign=L2&amp;url=http://www.laruence.com/2010/04/12/1396.html"  rel="external nofollow"  class="url" >Tweets that mention 深入理解SET NAMES和mysql(i)_set_charset的区别 | 风雪之隅 -- Topsy.com</a> writes: [...] This post was mentioned on Twitter by 高春辉, Angus Li. Angus Li said: 深入理解SET NAMES和mysql(i)_set_charset的区别 http://ff.im/-iUWcK [...]</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2502" >2010/04/13</a>, <a href="http://blog.panzhibiao.com"  rel="external nofollow"  class="url" >kevin</a> writes: addslashes(), str_replace()等等基于ascii编码的函数都会遇到这种问题。mysql_*系列有解决方案，别的有什么好的解决方案么？</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2503" >2010/04/13</a>, <a href="http://www.itphper.com/blog/?p=84"  rel="external nofollow"  class="url" >[转]深入理解SET NAMES和mysql(i)_set_charset的区别 - coder辉的it生涯</a> writes: [...] 本文地址: http://www.laruence.com/2010/04/12/1396.html [...]</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2504" >2010/04/13</a>, <a href="http://sanmuding.com"  rel="external nofollow"  class="url" >Anders</a> writes: 之前</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2505" >2010/04/13</a>, <a href="http://sanmuding.com"  rel="external nofollow"  class="url" >Anders</a> writes: 之前遇到这个问题，但是 使用的是PDO, 不知道如何解决。</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2506" >2010/04/13</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @Anders pdo找不到类似的方法,,,,,</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2507" >2010/04/13</a>, cz writes: 所以这两年我一看到SET NAMES的代码就要破口大骂，虽然utf-8编码里不存在5c问题

另外对于PDO，可以用prepared statement来解决。这也是一个比字符串过滤更好的防止注入的方法</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2508" >2010/04/13</a>, 好黑啊 writes: 非常good的文章，我very like</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2510" >2010/04/13</a>, <a href="http://hi.baidu.com/aleafs"  rel="external nofollow"  class="url" >aleafs</a> writes: 太清楚了</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2514" >2010/04/17</a>, <a href="http://www.jaceju.net/blog/?p=1108"  rel="external nofollow"  class="url" >網站製作學習誌 &raquo; [Web] 連結分享</a> writes: [...] 深入理解SET NAMES和mysql(i)_set_charset的区别 [...]</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2523" >2010/04/18</a>, Yufeng writes: 学习了，呵呵。</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2572" >2010/05/14</a>, <a href="http://www.bringsir.com"  rel="external nofollow"  class="url" >kazaff</a> writes: thx</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-2876" >2010/07/03</a>, <a href="http://www.lowest-rate-loans.com"  rel="external nofollow"  class="url" >OllieNoel</a> writes: Have no enough cash to buy a car? Worry no more, just because that is achievable to get the <a href="http://lowest-rate-loans.com/topics/credit-loans"  rel="nofollow" >credit loans</a> to solve such problems. Thus get a small business loan to buy everything you need.</li><li><a href="http://www.laruence.com/2010/04/12/1396.html#comment-3135" >2010/09/03</a>, <a href="http://54blues.com"  rel="external nofollow"  class="url" >blues</a> writes: 新手参上
竟然深入到C中了,C语言没怎么学会,看了个不大懂,自学的时候也没注意到这些问题,见识了,你的博客都很有深度啊,会经常来看的.目前还只能做做应用,无法深入到C,你这篇文章改变了我对php的理解,本以为可以不学C了,现在发现要深入学习还是需要知其根源,希望2年后毕业的时候也能有这样的深度.</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/04/12/1396.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Apache2中俩种设置PHP的异同</title>
		<link>http://www.laruence.com/2010/02/23/1310.html</link>
		<comments>http://www.laruence.com/2010/02/23/1310.html#comments</comments>
		<pubDate>Tue, 23 Feb 2010 06:18:19 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php源码]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1310</guid>
		<description><![CDATA[  Apache2开始引入了Hook方式, 对应的在PHP中也提供了apache2handler这种sapi. 
   

   和我之前介绍过的PHP lifecycle不同, 这种情况下的PHP, 通过注册handler钩子, 从而可以在handler hook阶段有机会处理请求, 通过判断请求的handler, 来确定是否需要处理, 如果需要就会调用自身的处理器.

    那么, 这种情况下也就有了多种配置方法,  主要考虑如下俩种方式...
]]></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/23/1310.html"  title="Permanet Link to Apache2中俩种设置PHP的异同" >http://www.laruence.com/2010/02/23/1310.html</a></li>
<li>转载请注明出处 </li>
</ul></div>
<p>
   Apache2开始引入了Hook方式, 对应的在PHP中也提供了apache2handler这种sapi. </p>
<p>   和我之前介绍过的PHP lifecycle不同, 这种情况下的PHP, 通过注册handler钩子, 从而可以在handler hook阶段有机会处理请求, 通过判断请求的handler, 来确定是否需要处理, 如果需要就会调用自身的处理器.</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;">
第一种:  AddType application/x-httpd-php .php
第二种:
      &lt;FilesMatch \.php$&gt;
          SetHandler application/x-httpd-php
     &lt;/FilesMatch&gt;
</pre>
<p>   首先来说, 这俩中方式的起作用的时刻不同,  对于第一种方式来说, 他是在type_check钩子阶段起作用的, 也就是在apache2src/modules/http/mod_mime.c中, 通过注册type_checker钩子, 加入find_ct(content_type), 在find_ct中, 通过配置文件中的mime映射, 或者是通过addType指令增加的映射, 根据文件的扩展来填充请求中的handler字段:</p>
<p>   而对于第二种方式, 是在fixup钩子阶段, 通过注册fixups钩子阶段加入core_override_type(apache2src/server/core.c)函数, 来将目录级的配置指令生效.</p>
<p>   而fixups钩子是晚于type_checker钩子的, 也是handler钩子之前最后的一个可以利用的钩子. 所以如果同时采用1,2俩种方式, 那么第二种方式会覆盖第一种方式设置的handler.</p>
<p>    其次, 俩种方式依赖的数据结构不同, 第一种方式依赖的是一个全局的mime对照表extension_mappings, 这个表由mime配置文件和AddType指令而来.</p>
<p>    而对于第二种方式, 它是根据配置文件构造的dir_config而来:</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;">
....
  core_dir_config *conf =
        (core_dir_config *)ap_get_module_config(r-&gt;per_dir_config,
                                                &amp;core_module);

    /* Check for overrides with ForceType / SetHandler
     */
    if (conf-&gt;mime_type &amp;&amp; strcmp(conf-&gt;mime_type, &quot;none&quot;))
        ap_set_content_type(r, (char*) conf-&gt;mime_type);

    if (conf-&gt;handler &amp;&amp; strcmp(conf-&gt;handler, &quot;none&quot;))
        r-&gt;handler = conf-&gt;handler;
.....
</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_c.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/02/23/1310.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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><li><a href="http://www.laruence.com/2010/02/03/1283.html#comment-2460" >2010/02/10</a>, yufeng writes: 前一阵子看到了，不过没有这篇文章详细，据说还要开源的。</li><li><a href="http://www.laruence.com/2010/02/03/1283.html#comment-2461" >2010/02/11</a>, jimmy writes: 是 c++ 而不是 c 的原因是什么呢，laruence.</li><li><a href="http://www.laruence.com/2010/02/03/1283.html#comment-2462" >2010/02/21</a>, Anonymous writes: 本来我想用的是C，而不是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/2010/02/03/1283.html/feed</wfw:commentRss>
		<slash:comments>5</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><li><a href="http://www.laruence.com/2010/02/02/1272.html#comment-2463" >2010/02/23</a>, darasion writes: json_encode 有没有类似这样的问题？</li><li><a href="http://www.laruence.com/2010/02/02/1272.html#comment-2469" >2010/03/07</a>, RainChen writes: 一般都会把这些封装到一个类，用静态方法调用，如
JSON::decode()
这样一来可以方便管理（归类、增加相关的方法），
二来可以避免PHP升级后的接口变异。
缺点是比直接调用原生的函数慢一点，但对比带来的可维护性的好处，这点效率牺牲完全可以忽略</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2010/02/02/1272.html/feed</wfw:commentRss>
		<slash:comments>8</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/><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/20/1247.html#comment-2465" >2010/03/01</a>, <a href="http://phpvim.net"  rel="external nofollow"  class="url" >verdana</a> writes: 尝试一下 fastcgi_split_path_info</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/20/1247.html/feed</wfw:commentRss>
		<slash:comments>1</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>深入理解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><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2483" >2010/03/25</a>, Anonymous writes: 怎么没有了，写完吧，大虾</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2826" >2010/06/22</a>, 库从志 writes: 博主 写得很深入</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-2979" >2010/07/25</a>, <a href="http://blog.haohtml.com/index.php/archives/4786"  rel="external nofollow"  class="url" >深入理解PHP原理之变量生命期(一) | haohtml&#39;s blog</a> writes: [...] 本文地址: http://www.laruence.com/2009/12/26/1198.html [...]</li><li><a href="http://www.laruence.com/2009/12/26/1198.html#comment-3071" >2010/08/08</a>, <a href="http://ichenkun.org/blog/2009/11/21/%e7%be%8e%e5%91%b3%e5%88%86%e4%ba%ab1/"  rel="external nofollow"  class="url" >美味分享1 | ichenkun</a> writes: [...] 5: 深入理解PHP原理之变量 生命期(一) [...]</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/12/26/1198.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><li><a href="http://www.laruence.com/2009/12/09/1180.html#comment-2660" >2010/05/26</a>, <a href="http://crazyphper.com"  rel="external nofollow"  class="url" >konakona</a> writes: 一般来讲，都是用===null这样子

另外is_null是函数，而isset是语句一看就知道前者要更慢一些。

而且用isset来判断null并不是最准确的。</li><li><a href="http://www.laruence.com/2009/12/09/1180.html#comment-3124" >2010/08/31</a>, <a href="http://www.166ck.com"  rel="external nofollow"  class="url" >Audio</a> writes: isset 是指变量是否声明了
is_null 是指变量的值是否为null,如果变量没声明，或报一个warning
empty 也是判断变量的值是否为空，但是变量不存则返回false</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>9</slash:comments>
		</item>
	</channel>
</rss>
