﻿<?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>Gavin&#039;s Blog &#187; 沉思录</title>
	<atom:link href="http://laigw.name/tag/%e6%b2%89%e6%80%9d%e5%bd%95/feed" rel="self" type="application/rss+xml" />
	<link>http://laigw.name</link>
	<description>Keep it simple, stupid. Simplicity is beauty.</description>
	<lastBuildDate>Sun, 29 Jan 2012 07:14:51 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>PHP沉思录之六：Drupal的性能问题</title>
		<link>http://laigw.name/post/202.html</link>
		<comments>http://laigw.name/post/202.html#comments</comments>
		<pubDate>Wed, 19 Nov 2008 03:49:55 +0000</pubDate>
		<dc:creator>Gavin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[沉思录]]></category>

		<guid isPermaLink="false">http://www.laigw.name/?p=202</guid>
		<description><![CDATA[本文发表在《程序员》杂志2008年第11期 
PHP沉思录之六：Drupal的性能问题
左轻侯
    Drupal是一个基于PHP的开源CMS系统，也是我认为技术上实现得最好的一个PHP应用。Drupal的架构非常优秀，通过微内核+plugin的方式，实现了极佳的扩展性，从而使Drupal远远超出一般的CMS这一范畴。从这个意义上来说，把Drupal称为Web OS似乎更加合适一些。关于Drupal，有太多的话可以说，也许我会在以后的时间里写一篇文章对它进行专门的讨论。但是在本文中，我想讨论的，是Drupal社区中的每一个人都会面对，但不是每一个人都对其有清晰认识的问题，即Drupal的性能问题。

    因为客户需求，我曾经对Drupal做过比较全面的测试。当时的环境是双服务器（DB server+Web Server），硬件配置都是单CPU+4G。数据库里面有几千条Node记录。用JMeter对各种情况下（开/关各种cache模块，logged user/anonymous user）不同页面的读取和写入操作都进行过测试。
测试的结果可能和很多人印象中不一样。两个主要的结果如下：
    1. Logged user和anonymous user的性能差距非常大。同一个页面，logged user的RPS(Requests per second)一般不超过20，而启用了cache的anonymous user的RPS在100多，当使用了file-based cache以后，甚至能超过300。
    2. 数据库压力相对较小。由于Drupal把大量可配置的内容都放在数据库中，因此往往容易产生这样一种印象，即Drupal对数据库要求应该是很高的。但事实上，无论是cache还是非cache模式，DB server的压力都相当小（CPU在10%以下），而Web Server的CPU在80%以上。跟踪所有的db query的执行时间后，也证明了这一点（全部db query的执行时间只占页面生成时间的一小部分）。 
    经过反复的测试和思考，我得出了一些结论。很明显，Drupal在大量logged user并发情况下的瓶颈，在于执行Drupal代码的CPU时间，而不是在于数据库或者其他地方。之所以出现这样的情况，和PHP本身的执行机制和Drupal的实现方式有关。Drupal在生成一个非cached的页面时，不管这个页面多么简单，都要执行一个完整的bootstrap过程，即使只启用了最少的模块，这个过程也要调用几十个PHP文件，执行成千上万行PHP代码。而PHP的机制又决定了没有任何PHP代码或者对象能够驻留内存，每次响应请求都必须执行完整的初始化工作。而anonymous user之所以快，是因为Drupal在执行cached page的时候，不会执行完整的bootstrap过程，它先检查是否cached page，是的话就读取缓存，然后结束工作。这样当然就快了。
以这个结论为前提，可以解释一些事情：
    1. 为什么Drupal的性能在各种环境下相差并不多。无论是双服务器，单服务器，甚至内存非常小的虚拟机，logged user的RPS值往往总是在10~20之间。数据库里面有几百条，或者几十万条记录，影响也不大。因为瓶颈并不在于DB或者内存，而是在于执行代码的过程。
    2. [...]]]></description>
		<wfw:commentRss>http://laigw.name/post/202.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP沉思录之五：Session有效期问题</title>
		<link>http://laigw.name/post/198.html</link>
		<comments>http://laigw.name/post/198.html#comments</comments>
		<pubDate>Tue, 18 Nov 2008 15:37:50 +0000</pubDate>
		<dc:creator>Gavin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Session]]></category>
		<category><![CDATA[沉思录]]></category>

		<guid isPermaLink="false">http://www.laigw.name/?p=198</guid>
		<description><![CDATA[本文发表在《程序员》杂志第10期 PHP沉思录之五：Session有效期问题 左轻侯 2008.9.07
Session处理是所有的Web应用都必须面对的问题。PHP中对session有效期的处理，和其他的解决方案有着很大的不同，这是和PHP的工作机制相关的。在传统的client/server应用中，对于session失效的情况，可以交给网络协议自己来处理。无论是client端主动关闭连接，还是因为网络异常而导致的连接中断，server端都能够得到通知，触发连接中断的事件。只要编程响应这一事件，执行指定的操作即可。但对于web应用来说，情况却完全不一样。HTTP协议本身是无状态的，也就是说，每当client/server完成一次请求/响应的过程后，连接就会被断开。在断开连接以后，server并不知道client是否继续“在线”，还会继续发送下一次请求。换句话说，无论client端的用户已经关闭了浏览器窗口，还是用户仅仅在阅读当前网页并准备在下一秒钟继续浏览，或者用户因为Windows崩溃/停电/硬盘坏掉/网线被拔/地球爆炸而彻底无法再发送下一个请求，server都一无所知。（在HTTP 1.1中，浏览器可以通过keep-alive参数，来通知server不要在响应请求后主动断开连接，从而实现物理上的长连接。但是，这只是为了提高网络传输的性能而采取的措施，HTTP在逻辑上仍然是无状态的。）因此，只能通过某种模拟的方式来判断当前session是否有效。如果某个session在超过一段时间后没有对server端发出请求，server都会判断用户已经“离线”，当前session失效，并触发连接中断的事件。要做到这一点，server需要运行一个后台线程，定时扫描所有的session信息，判断session是否已经超时。

PHP处理session的原理也不例外，但是在具体的实现方式上，却与众不同。这是因为，由于PHP的工作机制，它并没有一个后台线程，来定时地扫描session信息并判断其是否失效。它的解决之道是，当一个有效请求发生时，PHP会根据某个概率，来决定是否调用一个GC（Garbage Collector）。GC的工作，就是扫描所有的session信息，用当前时间减去session的最后修改时间（modified date），同配置参数（configuration option）session.gc_maxlifetime的值进行比较，如果生存时间已经超过gc_maxlifetime，就把该session删除。这是很容易理解的，因为如果每次请求都要调用GC代码，那么PHP的效率就会低得令人吃不消了。这个概率取决于配置参数 session.gc_probability/session.gc_divisor的值（可以通过php.ini或者ini_set()函数来修改）。默认情下，session.gc_probability = 1，session.gc_divisor=100，也就是说有1%的可能性会启动GC。这三个参数，session.gc_maxlifetime/session.gc_probability/session.gc_divisor都可以通过php.ini或者ini_set()函数来修改。但要记得，如果使用ini_set()函数的话，必须在每一个页面的开始处都调用ini_set()。
这又导致了另外一个问题，gc_maxlifetime只能保证session生存的最短时间，并不能够保存在超过这一时间之后session信息立即会得到删除。因为GC是按概率启动的，可能在某一个长时间内都没有被启动，那么大量的session在超过gc_maxlifetime以后仍然会有效。当然，发生这种情况的概率很小，但是如果你的应用对session的失效期要求很精确的话，这会导致很严重的问题。解决这个问题的一个方法是，把session.gc_probability/session.gc_divisor的机率提高，如果提到100%，就会彻底解决这个问题，但显然会对性能造成严重的影响。另一个方法是放弃PHP的GC，自己在代码中判断当前session的生存时间，如果超出了 gc_maxlifetime，就清空当前session。
PHP中的session有效期默认是1440秒（24分钟），也就是说，客户端超过24分钟没有刷新，当前session就会失效。要修改这个默认值，正确的解决办法是修改配置参数session.gc_maxlifetime。我曾经在网上搜索过这个问题的解决方式，找到的结果千奇百怪。有的说要设置“session_life_time”，据我知所，PHP中没有这个参数。有的说要调用session_set_cookie_params，或者设置session.cookie_lifetime，这仅仅用于设置client端cookie的生存时间，换言之，只当client端cookie的生存时间小于server端的session生存期时，修改这个值才有效，并且最长不能超过server端的session生存期，原因很简单，当server端的session已经失效时，client端cookie的生存时间再长也是没有意义的。还有的说要调用 session_cache_expire，这个参数用于通知浏览器和proxy，当前页面的内容应该被缓存多长时间，和session的生存期并没有直接关系。
听起来，这种解决方案很完美。但是，当你在实际中尝试修改session.gc_maxlifetime的值的时候，你很可能会发现，这个参数基本不起作用，session有效期仍然保持24分钟的默认值。甚至可能出现，在开发环境下工作正常，在服务器上却无效！
为了彻底解决这个问题，需要对PHP的工作细节进行进一步的分析。
在默认情况下，PHP 中的session信息会以文本文件的形式，被保存在系统的临时文件目录中。这个路径由配置参数session.save_path指定。在Linux下，这一路径通常为\tmp，在 Windows下通常为C:\Windows\Temp。当服务器上有多个PHP应用时，它们会把自己的session文件都保存在同一个目录中（因为它们使用同一个session.save_path参数）。同样地，这些PHP应用也会按一定机率启动GC，扫描所有的session文件。
问题在于，GC在工作时，并不会区分不同站点的session。举例言之，站点A的gc_maxlifetime设置为2小时，站点B的 gc_maxlifetime设置为默认的24分钟。当站点B的GC启动时，它会扫描公用的临时文件目录，把所有超过24分钟的session文件全部删除掉，而不管它们来自于站点A或B。这样，站点A的gc_maxlifetime设置就形同虚设了。
找到问题所在，解决起来就很简单了。在页面的开始处调用session_save_path()函数，它能够修改session.save_path参数，把保存session的目录指向一个专用的目录，例如\tmp\myapp\。这样，gc_maxlifetime参数就工作正常了。使用公用的session.save_path还会导致安全性问题，因为这意味着，同一台服务器上的其它PHP程序也可以读取你的站点的session文件，这可能被用于黑客攻击。另一个问题是效率：在一个繁忙的站点中，可能存在成千上万个session文件，而把许多不同网站的session文件都放在同一个目录下，无论是对单个文件的读写，还是遍历所有文件进行GC，都无疑会导致性能的降低。因此，如果你的PHP应用和别的PHP应用运行在同一台服务器上的话，强烈建议你使用自己的session.save_path。
严格地来说，这算是PHP的一个bug。当PHP在进行GC时，它应该区别来自不同站点的session文件，并应用不同的gc_maxlifetime值。目前，最新的PHP 5.2.X仍然存在这个问题。
上文说到，在一个繁忙的站点中，可能存在成千上万个session文件，即使区分了不同站点的session.save_path目录，单个站点的session文件数目仍然可能导致效率问题。为了解决这一问题，可行的几种方法有：
1、如果PHP运行在Linux系统下，使用ReiserFS文件系统取代默认的ext2/ext3文件系统。ReiserFS对于大量小文件的存取性能，比ext2/ext3有极大的提高。
2、将session.save_path指向一个内存路径。这意味着，session文件的读写只在内存中进行，而不执行磁盘操作。
3、session.save_path接受一个额外的N参数，用于指定目录的级数。例如，“5;/tmp” 将导致创建类似这样的session文件：/tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If。具体的说明，请参见：http://cn.php.net/manual/en/session.configuration.php#ini.session.save-path
4、终极的解决方案，是放弃PHP的session处理机制，自己编码接管所有的session处理操作，通过session_set_save_handler()函数来实现。通过自己接管session处理，可以将所有的session保存在专门的数据库（往往使用内存表）中，从而彻底解决session文件带来的问题，并且可以方便地实现session的共享和复制。这也是大型的PHP应用一般会使用的方式。关于session_set_save_handler()函数的使用，网上和相关图书都有详细的说明，这里不再赘述。值得一提的是，即使在这种方式下，启动GC的概率仍然取决于session.gc_probability/session.gc_divisor。
来源：http://www.bloggern.com/3835.html
]]></description>
		<wfw:commentRss>http://laigw.name/post/198.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP沉思录之四：Zend Framework</title>
		<link>http://laigw.name/post/194.html</link>
		<comments>http://laigw.name/post/194.html#comments</comments>
		<pubDate>Tue, 18 Nov 2008 12:05:37 +0000</pubDate>
		<dc:creator>Gavin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[沉思录]]></category>

		<guid isPermaLink="false">http://www.laigw.name/?p=194</guid>
		<description><![CDATA[PHP沉思录之四：Zend Framework 左轻侯 2007.11.11 
    从理论上来说，PHP是一种通用的动态语言，它可以替代Perl实现通用的脚本，甚至可以创建客户端GUI程序(通过GTK+)。但是，在实际应用中，PHP在绝大多数情况下都被用来开发Web应用。即使在Java和.NET这样有软件业界巨头支持的重量级竞争对手面前，出身草莽的PHP也毫不逊色，尤其是在应用最为广泛的轻量级web开发领域，PHP一直牢牢占据着领先的位置。在这一领域参与竞争的其他语言，例如Python和Perl，虽然各具特色，但是仍然无法撼动PHP的地位。PHP是当之无愧的“Web开发第一语言”，而且似乎没有什么能对它构成挑战。随着web应用在软件界的地位越来越重要，PHP也逐渐从脚本小子手中的玩具，转变成重要的工业语言，并获得了IBM这样的巨人的支持。
    但是，就在近两三年，一种新的Web开发解决方案的迅速崛起，震动了整个业界，让PHP开始感到王座不稳。这个解决方案，当然就是Ruby on Rails。
    本文无意对PHP和Ruby这两种语言进行全面的比较（虽然这的确是一个非常有意思的话题）。无论读者对Ruby和ROR持什么看法，有一点却是不争的事实：Ruby作为一种新的语言，虽然极具特色，但是并没有得到业界的普遍接受；只有在ROR诞生以后，以其惊人的生产力征服了无数开发者，Ruby这才一飞冲天。也就是说，Ruby至于在很大程度上是依靠ROR这个框架，才能起迅速崛起。

    对于感到严重威胁的PHP社区，如果要对Ruby进行有效的反击，这似乎是一条可行的道路：基于PHP语言，实现一个新的web开发框架，能够达到甚至超过ROR那样的生产力。这既是对Ruby的反击，其实也是PHP自身发展的必然结果。因为PHP在其发展过程中，早已经出现了数十个各种各样的框架，只是尚没有一个能具有ROR那样的生产力和影响力。
但是，实现这样一个框架，也面临着不少的问题：
    1、PHP语言本身能否完成这一任务？PHP原本只是用于快速解决web应用的简单脚本，虽然经过不断的发展，已经具有了许多高级的语言特征，但是是否能够实现象ROR那样精巧和强大的框架，能够达到ROR那样的生产力？
    2、PHP社群能否接受这样一个框架？PHP的使用者，大多数是脚本小子出身，习惯于快速、敏捷、直观的开发方式，对于重量级的框架，未必能够普遍认同。
　　
    无论这些问题的答案如何，重要的是，有人这么做了。Zend Framework就是这一思路的结果。
    如上所述，Zend Framework就是这样一个完全基于PHP语言的、向ROR学习的、针对web应用开发的框架。与其它同类的框架相比，Zend Framework有两个特点让它显得与众不同：
    1、Zend Framework由Zend公司开发，因此它是一个“官方的”框架。众所周知，Zend公司是PHP编译器的维护者，也是Zend Optimizer、Zend Studio等一系列PHP相关产品的拥有者。由于这一关系，Zend Framework虽然没有被内置到PHP发行包中，但也算得上PHP的官方解决方案了。（顺便说句题外话，Zend公司最近发布了Zend Studio for Eclipse的beta版本，有兴趣的读者不妨尝试一下。）
   [...]]]></description>
		<wfw:commentRss>http://laigw.name/post/194.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP沉思录之三：Smarty</title>
		<link>http://laigw.name/post/189.html</link>
		<comments>http://laigw.name/post/189.html#comments</comments>
		<pubDate>Tue, 18 Nov 2008 09:34:37 +0000</pubDate>
		<dc:creator>Gavin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Smarty]]></category>
		<category><![CDATA[沉思录]]></category>

		<guid isPermaLink="false">http://www.laigw.name/?p=189</guid>
		<description><![CDATA[PHP沉思录之三：Smarty 左轻侯 2007.8.11 
    在任何Web应用中，如何将程序代码和界面设计，或者说，将逻辑层和表现层分离开来，都会是一个问题。对于PHP这种类型的嵌入网页的脚本语言，这一问题尤其突出。在新手编写的代码中，把访问数据库的代码和操纵HTML元素的代码写在同一个页面里，是很常见的情况。为了避免这一问题，开发者倾向于将涉及业务逻辑的代码封装在某些单独的库文件中，再在负责显示界面的文件中将它们include进来。但是，这仍然无法避免在显示界面的文件中包含大量的PHP代码。究其所以然，是因为除了涉及业务逻辑的代码以外，即使仅仅在显示层，也往往涉及到复杂的显示逻辑。在一个典型的显示页面中，程序需要先包含所有必需的库文件，初始化上下文环境，创建相关业务逻辑对象（假如数据库访问代码已经被业务逻辑对象封装，可以节省数据库相关的代码），最后在HTML的空隙中把对象格式化为HTML元素进行显示。于是我们看到了无数这样的页面，在第一行HTML开始之前，就已经包含了数十行甚至更多的PHP代码，在HTML的内部，仍然充满了各种各样的PHP代码。因此，PHP代码和HTML代码搅和在一块的问题仍然无法解决，对HTML的修改仍然可能导致整个PHP程序崩溃。更加麻烦的是，这种不清晰的结构妨碍了PHP应用在规模上的进一步扩张。

    为了解决这一问题，模板（template）技术应运而生。模板技术的基本原理是，通过一个解析器（parser），读取指定的模板文件（包含了某些特定标签的HTML文件），将这些标签替换为相关的PHP变量，再输出为标准的HTML。通过这种方式，不但分离了业务逻辑层和表现层，而且也尽可能地分离了显示逻辑和HTML代码。通过替换不同的模板文件，可以方便地生成各种格式的输出，例如HTML，XML，WML，后期稍加处理甚至可以生成PDF和Flash。早期较为著名的PHP模板引擎有PHPLib中的Template和FastTemplate。
但是，模板技术也有其先天的缺陷：
	1、无法彻底分离逻辑。显示逻辑和HTML代码很难通过简单的标签替换，实现彻底的分离。例如，遍历并显示一个数组，在PHP中可以用简单的foreach语句实现，但是使用模板时，就需要进行对整个模板文件进行多次替换操作，造成效率的极大降低；或者根据不同的数据值显示不同的格式，如果模板文件完全不包含PHP代码，那么将很难做到这一点。
	2、解析导致的性能损失。由于每次PHP页面被访问时，解析器都必须对模板文件进行替换操作，无疑会降低PHP应用的性能。尤其在多次的替换操作时更是如此。因此，不使用模板比使用模板往往更加快速，这也是许多PHP程序员摒弃模板技术的原因之一。 
    在经过数年的发展之后，“编译型”的模板技术渐渐占据了主流。所谓“编译型”，是指解析器读取模板文件以后，并不直接生成静态HTML，而是“编译”成一个新的PHP文件，并将它保存起来。以后访问该页面时，模板引擎会直接执行“编译”后的PHP文件。Smarty是这种模板引擎的代表。
针对以上的两个问题，Smarty作了如下处理： 
	1、独立语法。Smarty实现了一套自己的语法，这套语法不但支持变量替换和简单的判断，而且支持循环，修饰符（modifier），内置了很多功能强大的函数，而且还支持自定义函数。这套系统保证Smarty能够完全独立地处理显示输出，无须再和PHP有什么瓜葛。事实上，在Smarty模板中，是不可以直接使用PHP代码的（通过显式定义可以使用），这也是一种强制分离逻辑层和表现层的方式。(理论上来说，Smarty的模板文件也可以应用于其它语言。)但是，这种解决方式也受到了指责，因为Smarty的语法过于强大，几乎变成了一门新的语言，指责者认为，这反而增加了复杂性。但是，根据作者的实际经验，Smarty的语法不但非常简单直观，而且只需要掌握一些最初级的语法，就足可以应付绝大多数的应用。即使是不懂编程的网页设计师，也很容易就能够掌握。
	2、编译机制。Smarty的“编译”机制，节省了用于反复解析模板文件的时间，极大地提高了速度。由于“编译”后生成的是标准的PHP文件，因此从理论上来说，执行的速度不会低于没有模板的PHP应用的速度。在一些和解析型模板引擎进行的对比测试中，Smarty在第一次访问时落后，但是在以后的访问中速度远远超出竞争对手。而且，这种编译过程是智能的，在模板文件的内容被改变后，Smarty会自动重新编译，因此对于开发者来说，编译过程完全无需人工干预。另外，如果你愿意的话，生成的PHP文件还可以方便地应用于Zend Accelerator这样的工具，进行二次编译。 
除此之外，Smarty还拥有其他一些优秀的特性： 
	1、缓存机制。由于实现了编译机制，在接收到对某个模板文件的访问请求时，Smarty会自动将它重定向到编译后的PHP文件。但是，这也意味着，Smarty也可以将它重定向到任何其他的文件——例如静态的HTML文件。在此基础之上，Smarty实现了自己的基于页面的缓存机制。Smarty能够将编译后的PHP文件产生的结果——静态HTML——保存起来，将重复发送的请求直接重定向给它，这意味着对于第一次之后的请求，不需要执行任何PHP代码（Smarty本身的代码当然除外）。对于不需要频繁更新的页面（我们知道这种网页往往在整个网站中占大多数），通过这种缓存机制获取的性能提升是惊人的。而且，由于它是在页面级实现的，因此完全无须涉及到复杂的对象级缓存问题，保持了逻辑上的简单性。
	2、可配置性。Smarty在开发之初就将高度的可配置性作为自己的一个设计目标。它本身以100%的PHP编写，以源代码的方式发行，只需要将Smarty简单地拷贝到你的文件路径中，就可以使用了。Smarty的各项配置变量，都可以通过修改config文件或者手动编码进行定制。例如，Smarty默认的定界符是花括号（{}），但是这往往和Javascript以及CSS中的花括号冲突。为了解决这一问题，可以简单地将默认定界符修改为其他的字符（例如ASP风格的“”）。
	3、可扩展性。Smart的实现基于面向对象的架构，并且提供了插件机制，非常便于用户修改和扩展其默认的认为。当然，你也可以直接修改它的源代码来达到目的。（对于基于脚本语言的开源应用来说，这是非常惬意的，因为你甚至不需要重新编译。） 
让我们来看一个最简单的Smarty应用。这个应用包括两个文件：
	TestSmarty.php 调用Smarty类库，初始化变量，并解析相应的模板文件
	TestSmarty.tpl 模板文件，其实就是包含了Smarty标签的HTML，放在指定的模板目录下，默认是./templates
　　
	TestSmarty.php的内容如下：

&#160;查看代码 PHP1
2
3
4
5
6
	&#60;?php 
	include_once&#40;&#34;./smarty/Smarty.class.php&#34;&#41;; 
	$Smarty = new Smarty&#40;&#41;; 
	$Smarty-&#62;assign&#40;&#34;HelloStr&#34;, &#34;Hello, world&#34;&#41;; 
	$Smarty-&#62;display&#40;&#34;TestSmarty.tpl&#34;&#41;; 
	?&#62;

这个文件的内容非常简单，任何有过PHP经验的程序员都应该能够理解：首先将Smarty类库所在的文件include进来，然后创建一个新的Smarty对象，并对HelloStr变量进行赋值，最后解析TestSmarty.tpl文件。
	TestSmarty.php的内容如下：

&#160;查看代码 PHP1
2
　　 
	This is a string from Smarty: &#123;$HelloStr&#125;

　　 
解析的结果为：
　

&#160;查看代码 PHP1
2
　 
	This is a string from Smarty: Hello, world

此时检查存放编译后的PHP文件的子目录（默认是./templates_c）,可以找到一个名叫%%65^650^65099D8B%%TestSmarty.tpl.php的文件，内容如下：
　

&#160;查看代码 PHP1
2
3
4
　 
	&#60;?php [...]]]></description>
		<wfw:commentRss>http://laigw.name/post/189.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP沉思录之二：PME模型</title>
		<link>http://laigw.name/post/185.html</link>
		<comments>http://laigw.name/post/185.html#comments</comments>
		<pubDate>Tue, 18 Nov 2008 08:37:59 +0000</pubDate>
		<dc:creator>Gavin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[PME]]></category>
		<category><![CDATA[PME模型]]></category>
		<category><![CDATA[沉思录]]></category>

		<guid isPermaLink="false">http://www.laigw.name/?p=185</guid>
		<description><![CDATA[本文发表在《程序员》第7期 PHP沉思录之二：PME模型 左轻侯 
在大规模的程序设计中，组件（component）已经成为一种非常流行的技术。常见的组件技术都基于PME模型，即属性（Property）、方法（Method）和事件（Event）。基于PME的组件技术可以方便地实现IoC（Inversion of Control，控制反转），是从IDE的plugin到应用服务器的“热发布”等许多技术的基础。
PHP从版本5开始，大大完善了对OO的支持，以前不能被应用的许多pattern现在都可以在PHP5中实现。因此，是否能够实现基于PHP的组件技术，也就成了一个值得讨论的问题。
下面对PHP对于PME模型的支持，逐一进行讨论：

1、属性（Property）
PHP并不支持类似Delphi或者C#的property语法，但这并不是问题。Java也不支持property语法，但是通过getXXX()和setXXX()的命名约定，同样可以支持属性。PHP也可以通过这一方式来支持属性。但是，PHP提供了另一种也许更好的方法，那就是__set()和__get()方法。
在PHP中，每一个class都会自动继承__set()和__get()方法。它们的定义如下：

&#160;查看代码 PHP1
2
void __set &#40; string name, mixed value &#41; 
mixed __get &#40; string name &#41;

这两个方法将在下列情况下被触发：当程序访问一个当前类没有显式定义的属性时。在这个时候，被访问的属性名称作为参数被传入相应的方法。任何类都可以重载__set()和__get()方法，以实现自己的功能。
如下例：

&#160;查看代码 PHP1
2
3
4
5
6
7
8
9
10
11
12
13
14
class PropertyTester &#123; 
&#160;
  public function __get&#40;$PropName&#41; &#123; 
    echo &#34;Getting Property $PropNamen&#34;; 
  &#125; 
&#160;
  public function __set&#40;$PropName, $Value&#41; &#123; 
    echo &#34;Setting Property $PropName [...]]]></description>
		<wfw:commentRss>http://laigw.name/post/185.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP沉思录之一：工作模型与数据库访问接口</title>
		<link>http://laigw.name/post/177.html</link>
		<comments>http://laigw.name/post/177.html#comments</comments>
		<pubDate>Tue, 18 Nov 2008 07:58:31 +0000</pubDate>
		<dc:creator>Gavin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[PAO]]></category>
		<category><![CDATA[工作原理]]></category>
		<category><![CDATA[工作模型]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[沉思录]]></category>
		<category><![CDATA[访问接口]]></category>

		<guid isPermaLink="false">http://www.laigw.name/?p=177</guid>
		<description><![CDATA[本文发表于《程序员》5月号，是一个系列的第一篇，目前想到的其他一些主题是：
　　
　　SQL注入问题
　　事件模型
　　AOP模型
　　UI Framework的实现
　　Template机制
　　
PHP沉思录&#8211;工作模型
　　
     PHP的工作模型非常特殊。从某种程度上说，PHP和ASP、ASP.NET、JSP/Servlet等流行的Web技术，有着本质上的区别。
     以Java为例，Java在Web应用领域，有两种技术：Java Servlet和JSP（Java Server Page）。Java Servlet是一种特殊类型的Java程序，它通过实现相关接口，处理Web服务器发送过来的请求，完成相应的工作。JSP在形式上是一种类似于PHP的脚本，但是事实上，它最后也被编译成Servlet。也就是说，在Java解决方案中，JSP和Servlet是作为独立的Java应用程序执行的，它们在初始化之后就驻留内存，通过特定的接口和Web服务器通信，完成相应工作。除非被显式地重启，否则它们不会终止。因此，可以在JSP和Servlet中使用各种缓存技术，例如数据库连接池。

     ASP.NET的机制与此类似。至于ASP，虽然也是一种解释型语言，但是仍然提供了Application对象来存放应用程序级的全局变量，它依托于ASP解释器在IIS中驻留的进程，在整个应用程序的生命期有效。
     PHP却完全不是这样。作为一种纯解释型语言，PHP脚本在每次被解释时进行初始化，在解释完毕后终止运行。这种运行是互相独立的，每一次请求都会创建一个单独的进程或线程，来解释相应的页面文件。页面创建的变量和其他对象，都只在当前的页面内部可见，无法跨越页面访问。在终止运行后，页面中申请的、没有被代码显式释放的外部资源，包括内存、数据库连接、文件句柄、Socket连接等，都会被强行释放。也就是说，PHP无法在语言级别直接访问跨越页面的变量，也无法创建驻留内存的对象。
     见下例：
　　

&#160;查看代码 PHP1
2
3
4
5
6
7
8
9
10
11
12
13
14
　　&#60;?php 
　　class StaticVarTester &#123; 
　　 public static $StaticVar = 0; 
　　&#125; 
　　 
　　function TestStaticVar&#40;&#41; &#123; 
　　 StaticVarTester :: $StaticVar += 1; 
　　 echo &#34;StaticVarTester [...]]]></description>
		<wfw:commentRss>http://laigw.name/post/177.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

