<?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>M78星云PHP</title>
	<atom:link href="http://liferar.com/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://liferar.com</link>
	<description>愿我们的梦想，像光那样，从一颗星到另一颗星!</description>
	<lastBuildDate>Wed, 07 Dec 2011 16:07:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>PHP中变量、引用和内存的对应关系</title>
		<link>http://liferar.com/relationship_between_variable_reference_and_memory_in_php</link>
		<comments>http://liferar.com/relationship_between_variable_reference_and_memory_in_php#comments</comments>
		<pubDate>Sun, 16 Oct 2011 05:46:23 +0000</pubDate>
		<dc:creator>CK猪</dc:creator>
				<category><![CDATA[CK猪是程序员]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://liferar.com/?p=440</guid>
		<description><![CDATA[今天在微博上看到一篇文章《PHP垃圾回收机制简单说明》，看了文中对于PHP中对于变量、内存和引用的关系说明，直觉告诉我，那是错误的。几年前写过一篇《PHP中=赋值操作符对不同数据类型的不同行为》，至今印象深刻。 《PHP垃圾回收机制简单说明》中说，“对变量 $a 进行 &#38; 操作,我的理解是找到 $a 所指向的内存,并为 $b 建立同样的一引用指向，并将存放字符串 I am test. 的内存块在符号表中引用计数 加 1.”。 这是错误的，我们可以做一个简单的实验。 &#60;?php class A { } $a = new A(); $b_a = $a; $b_r = &#38;$a; // 分别将$a、$b_a和$b_r赋值为NULL，看运行结果。 $a = NULL; //$b_a = NULL; //$b_r = NULL; echo &#8216;$a=&#8217;; var_dump($a); echo &#8216;$b_a=&#8217;; var_dump($b_a); echo &#8216;$b_r=&#8217;; var_dump($b_r); ?&#62; $a = [...]]]></description>
			<content:encoded><![CDATA[<p>今天在微博上看到一篇文章<a href="http://www.jzxue.com/wangzhankaifa/php/201007/22-4148.html">《PHP垃圾回收机制简单说明》</a>，看了文中对于PHP中对于变量、内存和引用的关系说明，直觉告诉我，那是错误的。几年前写过一篇<a href="http://liferar.com/behavior_of_assignment_operator_in_php">《PHP中=赋值操作符对不同数据类型的不同行为》</a>，至今印象深刻。</p>
<p><a href="http://www.jzxue.com/wangzhankaifa/php/201007/22-4148.html">《PHP垃圾回收机制简单说明》</a>中说，“对变量 $a 进行 &amp; 操作,我的理解是找到 $a 所指向的内存,并为 $b 建立同样的一引用指向，<span style="color: #444444; font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 22px;">并将存放字符串 I am test. 的内存块在符号表中引用计数 加 1.</span>”。</p>
<p>这是错误的，我们可以做一个简单的实验。</p>
<div id="_mcePaste">&lt;?php</div>
<div id="_mcePaste">class A {</div>
<div id="_mcePaste">}</div>
<div id="_mcePaste">$a = new A();</div>
<div id="_mcePaste">$b_a = $a;</div>
<div id="_mcePaste">$b_r = &amp;$a;</div>
<div>// 分别将$a、$b_a和$b_r赋值为NULL，看运行结果。</div>
<div id="_mcePaste">$a = NULL;</div>
<div id="_mcePaste">//$b_a = NULL;</div>
<div id="_mcePaste">//$b_r = NULL;</div>
<div id="_mcePaste">echo &#8216;$a=&#8217;;</div>
<div id="_mcePaste">var_dump($a);</div>
<div id="_mcePaste">echo &#8216;$b_a=&#8217;;</div>
<div id="_mcePaste">var_dump($b_a);</div>
<div id="_mcePaste">echo &#8216;$b_r=&#8217;;</div>
<div id="_mcePaste">var_dump($b_r);</div>
<div>?&gt;</div>
<div>$a = NULL的运行结果：</div>
<div>
<div>$a=NULL</div>
<div>$b_a=object(A)#1 (0) {</div>
<div>}</div>
<div>$b_r=NULL</div>
</div>
<div>$b_a = NULL的运行结果：</div>
<div>
<div>$a=object(A)#1 (0) {</div>
<div>}</div>
<div>$b_a=NULL</div>
<div>$b_r=object(A)#1 (0) {</div>
<div>}</div>
</div>
<div>$b_r = NULL的运行结果：</div>
<div>
<div>$a=NULL</div>
<div>$b_a=object(A)#1 (0) {</div>
<div>}</div>
<div>$b_r=NULL</div>
</div>
<div>具体过程我不分析了，结论就是<span style="color: #ff0000;">变量是某块内存的别名，而引用则是某个变量的别名<span style="color: #000000;">。并且，<span style="color: #ff0000;">创建一个引用指向变量$a并没有将$a所指向的内存引用计数加1</span>。</span></span></div>
<div><span style="color: #ff0000;"><span style="color: #000000;"><br />
</span></span></div>
<h3>相关文章</h3>
<ul class="related_posts">
<li><a href="http://liferar.com/buffer_control_in_php" title="PHP输出缓存控制" rel="bookmark inlinks">PHP输出缓存控制</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/httpd_php_compile_parameters" title="httpd、php编译参数" rel="bookmark inlinks">httpd、php编译参数</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/alipay_problems_technical_support" title="支付宝集成经验之技术支持问题" rel="bookmark inlinks">支付宝集成经验之技术支持问题</a><span class="count">( 8 )</span></li>
<li><a href="http://liferar.com/behavior_of_assignment_operator_in_php" title="PHP中=赋值操作符对不同数据类型的不同行为" rel="bookmark inlinks">PHP中=赋值操作符对不同数据类型的不同行为</a><span class="count">( 2 )</span></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://liferar.com/relationship_between_variable_reference_and_memory_in_php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>支付宝集成经验之技术支持问题</title>
		<link>http://liferar.com/alipay_problems_technical_support</link>
		<comments>http://liferar.com/alipay_problems_technical_support#comments</comments>
		<pubDate>Sat, 25 Apr 2009 10:10:07 +0000</pubDate>
		<dc:creator>CK猪</dc:creator>
				<category><![CDATA[CK猪是程序员]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[支付宝]]></category>

		<guid isPermaLink="false">http://liferar.com/?p=93</guid>
		<description><![CDATA[经过三天的努力，终于把接口调通了。在调试的过程中，遇到了一些文档中未提到的问题。而且也发现了文档和PHP编程接口的一些缺陷和错误。 这些缺陷和错误可能给开发者带来了一些误导。 文档错误： 1）所有的文档中都把错误代码HAS_NO_PRIVILEGE(没有权限访问该服务)写成HASNO_PRIVILEGE。   文档缺陷： 1）文档《标准快速付款接口文档 V2.0》和《批量付款到帐号》中关于数字签名部分有内容不明确。 《标准快速付款接口文档 V2.0》5.2.4. 支付宝系统返回处理结果： 支付宝系统接收到商户系统发起的请求，处理成功后返回的参数中同样包含有参数sign、sign_type，商户需根据sign_type 计算sign 值，最终检验支付宝系统返回的sign 值，这里要注意的是商户需要对每一个返回参数的值先进行decode 后再验证sign。 这里的decode我的理解应该是转换编码的意思吧?!但第一次看会很直觉地以为是urldecode。 2）文档中没有提到，本地以某种编码提交给支付宝，支付宝在发通知的时候就会以该编码对数据进行编码并发回本地。虽然这是比较容易想到的，但是文档还是应该说清楚。毕竟，搞错编码是网络传输中经常会出问题。 3）支付宝返回到我的return_url中的参数中，is_success这个参数没有说明，虽然字面就看得出来，但是写到文档里也没什么不好吧。 4）文档《标准快速付款接口文档 V2.0》中没有错误代码TRADE_SELLER_NOT_MATCH，网上查了好像是网址不匹配还是什么原因，不清楚。重现方法：用测试帐号***@***.com发个out_trade_no为1的请求就会出现。 5）文档中还没提到，当网站使用非第三方权威机构签名的SSL证书时，将收不到支付宝的notify。确认已经加了notify_url。 PHP编程接口缺陷： 1）编程接口及示例代码写得过于随便，出现明显的错误 批量支付示例代码index.php中 "pay_date" => date(Ymd), //付款日期 格式20070412 应为 "pay_date" => date('Ymd'), //付款日期 格式20070412 "batch_no" => date(Ymdhms) , //批量付款订单号 应为 "batch_no" => date('Ymdhms') , //批量付款订单号 出现这个错误，说明了支付宝在发demo代码给用户时没有先测试，至少是发给我的这份没有，因为这个demo是不可能运行得起来的。 2）alipay_service.php中 if($parameter['_input_charset'] == "") 应为 if (array_key_exists('_input_charset', [...]]]></description>
			<content:encoded><![CDATA[<p>
经过三天的努力，终于把接口调通了。在调试的过程中，遇到了一些文档中未提到的问题。而且也发现了文档和PHP编程接口的一些缺陷和错误。<br />
这些缺陷和错误可能给开发者带来了一些误导。
</p>
<p>
文档错误：<br />
1）所有的文档中都把错误代码HAS_NO_PRIVILEGE(没有权限访问该服务)写成HASNO_PRIVILEGE。
</p>
<p> <br />
文档缺陷：<br />
1）文档《标准快速付款接口文档 V2.0》和《批量付款到帐号》中关于数字签名部分有内容不明确。<br />
《标准快速付款接口文档 V2.0》5.2.4. 支付宝系统返回处理结果：</p>
<blockquote><p>
支付宝系统接收到商户系统发起的请求，处理成功后返回的参数中同样包含有参数sign、sign_type，商户需根据sign_type 计算sign 值，最终检验支付宝系统返回的sign 值，这里要注意的是商户需要对每一个返回参数的值先进行decode 后再验证sign。
</p></blockquote>
<p>
这里的decode我的理解应该是转换编码的意思吧?!但第一次看会很直觉地以为是urldecode。
</p>
<p>
2）文档中没有提到，本地以某种编码提交给支付宝，支付宝在发通知的时候就会以该编码对数据进行编码并发回本地。虽然这是比较容易想到的，但是文档还是应该说清楚。毕竟，搞错编码是网络传输中经常会出问题。<br />
3）支付宝返回到我的return_url中的参数中，is_success这个参数没有说明，虽然字面就看得出来，但是写到文档里也没什么不好吧。<br />
4）文档《标准快速付款接口文档 V2.0》中没有错误代码TRADE_SELLER_NOT_MATCH，网上查了好像是网址不匹配还是什么原因，不清楚。重现方法：用测试帐号***@***.com发个out_trade_no为1的请求就会出现。<br />
5）文档中还没提到，当网站使用非第三方权威机构签名的SSL证书时，将收不到支付宝的notify。确认已经加了notify_url。
</p>
<p>
PHP编程接口缺陷：<br />
1）编程接口及示例代码写得过于随便，出现明显的错误<br />
批量支付示例代码index.php中</p>
<pre lang="php" line="21">
"pay_date" => date(Ymd),  //付款日期 格式20070412
</pre>
<p>应为</p>
<pre lang="php" line="21">
"pay_date" => date('Ymd'),  //付款日期 格式20070412
</pre>
<pre lang="php" line="25">
"batch_no"  => date(Ymdhms) , //批量付款订单号
</pre>
<p>应为</p>
<pre lang="php" line="25">
"batch_no"  => date('Ymdhms') , //批量付款订单号
</pre>
</p>
<p>
出现这个错误，说明了支付宝在发demo代码给用户时没有先测试，至少是发给我的这份没有，因为这个demo是不可能运行得起来的。
</p>
<p>
2）alipay_service.php中
</p>
<pre lang="php" line="26">
if($parameter['_input_charset'] == "")
</pre>
<p>应为</p>
<pre lang="php" line="26">
if (array_key_exists('_input_charset', $parameter))
</pre>
<p><p>
否则，当传进来的$parameter不包含_input_charset项是会出现错误Undefined index: _input_charset
</p>
<p>
3)编程接口能写得完善一些，实现DSA签名和RAS签名功能
</p>
<p>
另外，demo代码中把提交表单的按钮放到form外面了。一开始我没注意为什么要这么做，后来遇到签名错误时，弄了一个小时才发现，原来的我把提交按钮放到了FORM里面，并给了提交按钮一个name属性。这导致了提交到支付宝的数据中多了一项，导致签名错误。这是一个很隐蔽的陷阱，在文档中明确提醒集成开发者，相信会对集成开发者有很大的帮助。避免像我一样浪费了一个小时才找到错误原因。
</p>
<h3>相关文章</h3>
<ul class="related_posts">
<li><a href="http://liferar.com/behavior_of_assignment_operator_in_php" title="PHP中=赋值操作符对不同数据类型的不同行为" rel="bookmark inlinks">PHP中=赋值操作符对不同数据类型的不同行为</a><span class="count">( 2 )</span></li>
<li><a href="http://liferar.com/buffer_control_in_php" title="PHP输出缓存控制" rel="bookmark inlinks">PHP输出缓存控制</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/httpd_php_compile_parameters" title="httpd、php编译参数" rel="bookmark inlinks">httpd、php编译参数</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/relationship_between_variable_reference_and_memory_in_php" title="PHP中变量、引用和内存的对应关系" rel="bookmark inlinks">PHP中变量、引用和内存的对应关系</a><span class="count">( 0 )</span></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://liferar.com/alipay_problems_technical_support/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>httpd、php编译参数</title>
		<link>http://liferar.com/httpd_php_compile_parameters</link>
		<comments>http://liferar.com/httpd_php_compile_parameters#comments</comments>
		<pubDate>Thu, 16 Apr 2009 11:09:02 +0000</pubDate>
		<dc:creator>CK猪</dc:creator>
				<category><![CDATA[CK猪是程序员]]></category>
		<category><![CDATA[httpd]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://liferar.com/?p=90</guid>
		<description><![CDATA[PHP编译参数 CFLAGS="-O2" ./configure --prefix=/usr/local --with-config-file-path=/etc \ --with-apxs2=/usr/local/httpd/bin/apxs --with-libdir=lib --with-mysql=no \ --disable-ipv6 --disable-tokenizer --disable-short-tags --enable-mbstring=shared \ --with-gettext=shared --with-regex=php --with-freetype-dir=/usr/local --with-gd=shared \ --with-png-dir=/usr/local --with-jpeg-dir=/usr/local --with-pdo-mysql=shared,/usr/local/mysql \ --enable-pdo=shared --with-pdo-sqlite=shared --with-sqlite=shared --with-openssl-dir=/usr/local/openssl \ --with-openssl=/usr/local APR编译参数 CFLAGS="-O2" ./configure --prefix=/usr/local APR-UTIL编译参数 CFLAGS="-O2" ./configure --prefix=/usr/local/apr-util/ --with-apr=/usr/local/apr --with-mysql=/usr/local/mysql/ HTTPD编译参数 LDFLAGS="-L/usr/local/apr/lib" ./configure --prefix=/usr/local/httpd --with-apr=/usr/local/apr \ --with-ssl=/usr/local/openssl --enable-mods-shared=all --enable-so --with-apr-util=/usr/local/apr-util \ --enable-modules=all --enable-isapi=shared --enable-cgi=shared --enable-ssl=shared [...]]]></description>
			<content:encoded><![CDATA[<p>PHP编译参数</p>
<pre lang="conf">CFLAGS="-O2" ./configure --prefix=/usr/local --with-config-file-path=/etc \
--with-apxs2=/usr/local/httpd/bin/apxs  --with-libdir=lib --with-mysql=no  \
--disable-ipv6 --disable-tokenizer --disable-short-tags --enable-mbstring=shared  \
--with-gettext=shared --with-regex=php --with-freetype-dir=/usr/local --with-gd=shared \
--with-png-dir=/usr/local --with-jpeg-dir=/usr/local --with-pdo-mysql=shared,/usr/local/mysql \
--enable-pdo=shared --with-pdo-sqlite=shared --with-sqlite=shared --with-openssl-dir=/usr/local/openssl \
--with-openssl=/usr/local</pre>
<p>APR编译参数</p>
<pre lang="conf">CFLAGS="-O2" ./configure --prefix=/usr/local</pre>
<p>APR-UTIL编译参数</p>
<pre lang="conf">CFLAGS="-O2" ./configure --prefix=/usr/local/apr-util/ --with-apr=/usr/local/apr --with-mysql=/usr/local/mysql/</pre>
<p>HTTPD编译参数</p>
<pre lang="conf">LDFLAGS="-L/usr/local/apr/lib" ./configure --prefix=/usr/local/httpd --with-apr=/usr/local/apr  \
--with-ssl=/usr/local/openssl --enable-mods-shared=all --enable-so --with-apr-util=/usr/local/apr-util \
--enable-modules=all --enable-isapi=shared --enable-cgi=shared --enable-ssl=shared</pre>
<h3>相关文章</h3>
<ul class="related_posts">
<li><a href="http://liferar.com/alipay_problems_technical_support" title="支付宝集成经验之技术支持问题" rel="bookmark inlinks">支付宝集成经验之技术支持问题</a><span class="count">( 8 )</span></li>
<li><a href="http://liferar.com/behavior_of_assignment_operator_in_php" title="PHP中=赋值操作符对不同数据类型的不同行为" rel="bookmark inlinks">PHP中=赋值操作符对不同数据类型的不同行为</a><span class="count">( 2 )</span></li>
<li><a href="http://liferar.com/relationship_between_variable_reference_and_memory_in_php" title="PHP中变量、引用和内存的对应关系" rel="bookmark inlinks">PHP中变量、引用和内存的对应关系</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/buffer_control_in_php" title="PHP输出缓存控制" rel="bookmark inlinks">PHP输出缓存控制</a><span class="count">( 0 )</span></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://liferar.com/httpd_php_compile_parameters/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP中=赋值操作符对不同数据类型的不同行为</title>
		<link>http://liferar.com/behavior_of_assignment_operator_in_php</link>
		<comments>http://liferar.com/behavior_of_assignment_operator_in_php#comments</comments>
		<pubDate>Sat, 28 Mar 2009 19:24:25 +0000</pubDate>
		<dc:creator>CK猪</dc:creator>
				<category><![CDATA[CK猪是程序员]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[引用]]></category>

		<guid isPermaLink="false">http://www.liferar.com/?p=21</guid>
		<description><![CDATA[作为一个PHP的新手，一直对PHP的引用困惑了很久，今晚仔细看了用户手册和做了一些实验，终于明白了其中的原理和细节，特别是＝操作符对于不同类型的不同行为。 首先解释赋值操作符＝的行为，看下面的例子： $i = 0; $j = $i; $j = 0; echo $i; // 打印输出0 $arr = array(0); $arr2 = $arr; $arr2[0] = 1; echo $arr[0]; //打印输出0 class B { public $i = 0; } $b = new B(); $c = $b; $c-&#62;i = 1; echo($b-&#62;i); // 打印输出1 从这个例子可以看出，如果＝操作符右边的变量为基本数据类型或者数组，那么＝操作符把右边变量的一份拷贝赋值给左边变量；如果右边变量不是基本数据类型或者数组，如class，那么＝会把一个指向右边变量的引用赋值给左边变量。注意：是指向右边变量的引用，而不是指向右边变量所指的内容区域的引用；具体看下边的例子 $a = new A(); $b_a = [...]]]></description>
			<content:encoded><![CDATA[<p>作为一个PHP的新手，一直对PHP的引用困惑了很久，今晚仔细看了用户手册和做了一些实验，终于明白了其中的原理和细节，特别是＝操作符对于不同类型的不同行为。<br />
首先解释赋值操作符＝的行为，看下面的例子：</p>
<pre lang="php">$i = 0;
$j = $i;
$j = 0;
echo $i;   // 打印输出0

$arr = array(0);
$arr2 = $arr;
$arr2[0] = 1;
echo $arr[0]; //打印输出0

class B
{
    public $i = 0;
}

$b = new B();
$c = $b;
$c-&gt;i = 1;
echo($b-&gt;i);  // 打印输出1</pre>
<p>从这个例子可以看出，如果＝操作符右边的变量为基本数据类型或者数组，那么＝操作符把右边变量的一份拷贝赋值给左边变量；如果右边变量不是基本数据类型或者数组，如class，那么＝会把一个指向右边变量的引用赋值给左边变量。注意：是指向右边变量的引用，而不是指向右边变量所指的内容区域的引用；具体看下边的例子</p>
<pre lang="php">$a = new A();
$b_a = $a;
$b_r = &amp;$a;

$b_a = null;
var_dump($a);  //打印 object(A)[2]，$a所指向的内容还在
$b_r = null;
var_dump($a); // 打印 null，$a所指向的内容被清除了</pre>
<p>上面的例子也说明了，如果用 $var = &amp;$a 的方式赋值的话，用$var=null来销毁变量$var的话事实上是把$var所指内容被设置null了，其实这句话也暗示了任何一个指向该内容区域的引用变量均可用来销毁该内容区域的内容。所以，要销毁变量$var的话用 unset($var) 。PS：事实上一这种方式赋值$var只是个引用，占用不了多少内存，要不要销毁没所谓，这里这是说下必须用unset的方式销毁。</p>
<p>下面则是《用户手册》中的“引用的解释”的例子：</p>
<pre lang="php">$a =&amp; $b;</pre>
<p>下边有这么一句解释：<br />
这意味着 $a 和 $b 指向了同一个变量。<br />
注: $a 和 $b 在这里是完全相同的，这并不是 $a 指向了 $b 或者相反，而是 $a 和 $b 指向了同一个地方。<br />
引用是什么？</p>
<blockquote><p>在 PHP 中引用意味着用不同的名字访问同一个变量内容。这并不像 C 的指针，替代的是，引用是符号表别名。注意在 PHP 中，变量名和变量内容是不一样的，因此同样的内容可以有不同的名字。最接近的比喻是 Unix 的文件名和文件本身――变量名是目录条目，而变量内容则是文件本身。引用可以被看作是 Unix 文件系统中的紧密连接。</p></blockquote>
<p>关于“引用是什么”的一点解释：</p>
<pre lang="php">int i = 0;
int j = 0;
int *p = &amp;i;
p = &amp;j;</pre>
<p>上面的代码中，p是一个指向i的内存地址的指针，而*p才是其中的内容；p=&amp;j指向改变了p指针的指向，用*p=111的表达式才会改变i的内容。而PHP中则不是，下面的例子</p>
<pre lang="php">$i = 0;
$p = &amp;$i;</pre>
<p>$p = 111则马上会改变$i的值。<br />
<h3>相关文章</h3>
<ul class="related_posts">
<li><a href="http://liferar.com/buffer_control_in_php" title="PHP输出缓存控制" rel="bookmark inlinks">PHP输出缓存控制</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/relationship_between_variable_reference_and_memory_in_php" title="PHP中变量、引用和内存的对应关系" rel="bookmark inlinks">PHP中变量、引用和内存的对应关系</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/alipay_problems_technical_support" title="支付宝集成经验之技术支持问题" rel="bookmark inlinks">支付宝集成经验之技术支持问题</a><span class="count">( 8 )</span></li>
<li><a href="http://liferar.com/httpd_php_compile_parameters" title="httpd、php编译参数" rel="bookmark inlinks">httpd、php编译参数</a><span class="count">( 0 )</span></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://liferar.com/behavior_of_assignment_operator_in_php/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PHP输出缓存控制</title>
		<link>http://liferar.com/buffer_control_in_php</link>
		<comments>http://liferar.com/buffer_control_in_php#comments</comments>
		<pubDate>Sat, 28 Mar 2009 14:48:37 +0000</pubDate>
		<dc:creator>CK猪</dc:creator>
				<category><![CDATA[CK猪是程序员]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WEB]]></category>
		<category><![CDATA[缓存]]></category>

		<guid isPermaLink="false">http://www.liferar.com/?p=9</guid>
		<description><![CDATA[有时我们需要页面内容完成生成后一次性输出，或者echo之后马上输出页面内存而不缓存，那么我们就会用到PHP的页面输出缓存控制的相关函数。 PHP页面输出缓存控制函数如下： flush &#8212; 刷新输出缓冲 ob_clean &#8212; Clean (erase) the output buffer ob_end_clean &#8212; Clean (erase) the output buffer and turn off output buffering ob_end_flush &#8212; Flush (send) the output buffer and turn off output buffering ob_flush &#8212; Flush (send) the output buffer ob_get_clean &#8212; Get current buffer contents and delete current output buffer ob_get_contents [...]]]></description>
			<content:encoded><![CDATA[<p>有时我们需要页面内容完成生成后一次性输出，或者echo之后马上输出页面内存而不缓存，那么我们就会用到PHP的页面输出缓存控制的相关函数。</p>
<p>PHP页面输出缓存控制函数如下：</p>
<blockquote><p>flush &#8212; 刷新输出缓冲<br />
ob_clean &#8212; Clean (erase) the output buffer<br />
ob_end_clean &#8212; Clean (erase) the output buffer and turn off output buffering<br />
ob_end_flush &#8212; Flush (send) the output buffer and turn off output buffering<br />
ob_flush &#8212; Flush (send) the output buffer<br />
ob_get_clean &#8212; Get current buffer contents and delete current output buffer<br />
ob_get_contents &#8212; Return the contents of the output buffer<br />
ob_get_flush &#8212; Flush the output buffer, return it as a string and turn off output buffering<br />
ob_get_length &#8212; Return the length of the output buffer<br />
ob_get_level &#8212; Return the nesting level of the output buffering mechanism<br />
ob_get_status &#8212; Get status of output buffers<br />
ob_gzhandler &#8212; ob_start callback function to gzip output buffer<br />
ob_implicit_flush &#8212; Turn implicit flush on/off<br />
ob_list_handlers &#8212; List all output handlers in use<br />
ob_start &#8212; Turn on output buffering<br />
output_add_rewrite_var &#8212; Add URL rewriter values<br />
output_reset_rewrite_vars &#8212; Reset URL rewriter values</p></blockquote>
<p>更加详细的用法见PHP用户手册，下面举一个简单的示例:</p>
<pre lang="php" line="1">
$str = 'Hello world';
echo $str;
sleep(10);
</pre>
<p>这段代码会在sleep了10秒后在页面打印 Hello world。在看下面这段代码：</p>
<pre lang="php" line="1">
$str = 'Hello world';
echo $str . str_repeat(' ', 256);
ob_flush();
flush();
sleep(10);
</pre>
<p>这段代码则会马上在屏幕上打印 Hello world。关键就在于第2和第3行调用的两个函数 ob_flush() 和 flush()。这两个函数得一起使用才能保证页面马上输出Hello world。其中str_repeat(&#8216; &#8216;, 256)则是为了解决某些浏览器必须在接收到256个字符后才会显示内容。下面的内容摘自《PHP用户手册》，很好地解释了上面的代码意图。<br />
引用自《PHP用户手册》的内容</p>
<blockquote><p>
flush() 函数不会对服务器或客户端浏览器的缓存模式产生影响。因此，必须同时使用 ob_flush() 和flush() 函数来刷新输出缓冲。<br />
个别web服务器程序，特别是Win32下的web服务器程序，在发送结果到浏览器之前，仍然会缓存脚本的输出，直到程序结束为止。<br />
有些Apache的模块，比如mod_gzip，可能自己进行输出缓存，这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。<br />
甚至浏览器也会在显示之前，缓存接收到的内容。例如 Netscape 浏览器会在接受到换行或 html 标记的开头之前缓存内容，并且在接受到  标记之前，不会显示出整个表格。<br />
一些版本的 Microsoft Internet Explorer 只有当接受到的256个字节以后才开始显示该页面，所以必须发送一些额外的空格来让这些浏览器显示页面内容。
</p></blockquote>
<p>上面的代码演示了即时输出缓存，一般情况下该部分代码都能正常完成所要的功能，但是也会有例外</p>
<p>1）服务器打开了gzip等压缩功能，导致输出的缓存被压缩后不足256字节，那么在某些版本IE中也会等到凑够了256字节才输出内容（PS:之所以说某些版本的IE是因为我现在用的IE6就没有该问题，WINDOWS XP SP2)</p>
<p>2)如果这段代码之前还有代码，而且前面的代码中多次调用了ob_start()而ob_end_flush()调用的次数比ob_start()少2次，那么这上面的代码也不能正常工作。因为ob_start()的buffer是stackable的。调用多次ob_start()后，ob_flush()只会把buffer输出到上一层的buffer中。例如</p>
<p>调用ob_start()，它的缓存区为 buffer1，再次调用ob_start()，它的缓存区为buffer2。这时调用ob_flush()只会把 buffer2中的内容输出到 buffer1。这时如果调用 ob_end_flush(), 那么buffer2中的内容会被输出到 buffer1并且销毁buffer2。此时再调用ob_flush()就会把buffer1中的内容输出到服务器，然后调用flush()则可以把服务器中的buffer输出到客户端浏览器。</p>
<p>知道了ob_start()和ob_end_flush()的用法后，就可以用下面的代码来实现所有页面内容完全生成后一次性输出所有的缓存。</p>
<pre lang="php" line="1">
ob_start();

//do something to generate $content
echo $content;

ob_end_flush();
flush(); //if script is ending, this can be removed.
</pre>
<p>之所以要这么做是因为服务器会在缓存区满了以后就输出缓存而不是等到所以页面内容生成后再输出<br />
<h3>相关文章</h3>
<ul class="related_posts">
<li><a href="http://liferar.com/html_seldom_used_attribute_list" title="HTML不常用标签属性备忘" rel="bookmark inlinks">HTML不常用标签属性备忘</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/web_dev_problem" title="WEB前端开发的一些问题备忘" rel="bookmark inlinks">WEB前端开发的一些问题备忘</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/return_value_of_new_function" title="javascript中new function()的返回值（并不一定是function的“实例”）" rel="bookmark inlinks">javascript中new function()的返回值（并不一定是function的“实例”）</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/httpd_php_compile_parameters" title="httpd、php编译参数" rel="bookmark inlinks">httpd、php编译参数</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/mootools_bugs_date_getweek" title="Mootools Bug - Date.getWeek" rel="bookmark inlinks">Mootools Bug &#8211; Date.getWeek</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/relationship_between_variable_reference_and_memory_in_php" title="PHP中变量、引用和内存的对应关系" rel="bookmark inlinks">PHP中变量、引用和内存的对应关系</a><span class="count">( 0 )</span></li>
<li><a href="http://liferar.com/alipay_problems_technical_support" title="支付宝集成经验之技术支持问题" rel="bookmark inlinks">支付宝集成经验之技术支持问题</a><span class="count">( 8 )</span></li>
<li><a href="http://liferar.com/behavior_of_assignment_operator_in_php" title="PHP中=赋值操作符对不同数据类型的不同行为" rel="bookmark inlinks">PHP中=赋值操作符对不同数据类型的不同行为</a><span class="count">( 2 )</span></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://liferar.com/buffer_control_in_php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

