<?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/"
	>

<channel>
	<title> PHP5研究室</title>
	<atom:link href="http://www.phpv.net/rss" rel="self" type="application/rss+xml" />
	<link>http://www.phpv.net/</link>
	<description>PHP5研究室是提供PHP,mysql,linux,apache,WEB标准等精华文章的网站</description>
	<pubDate>Fri, 19 Mar 2010 18:45:41 +0800</pubDate>
	<generator>Chiron ver1.0</generator>
	<language>zh-cn</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
									<item>
					<title>Save Mysql  拯救MySQL! </title>
					<link>http://www.phpv.net/html/1709.html</link>
					<comments>http://www.phpv.net/html/1709.html#comment</comments>
					<pubDate>Thu, 28 Jan 2010 19:22:41 +0800</pubDate>
					<dc:creator></dc:creator>
					<category><![CDATA[数据库技术]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1709.html</guid>
					<description><![CDATA[为阻止Oracle收购Sun，在欧盟似乎已决定批准这项70亿美元的收购案之后，MySQL数据库创始人开始寻求中国和俄罗斯帮助。

在一封给中国 MySQL用户的邮件中写道 “亲爱的拯救MySQL的中国签名支持者，欧盟可能无法拯救MySQL, 中国和俄罗斯可能是拯救MySQL的希望之所在。中国拥有强大、独立以及自信的反垄断主管机关，因此，我本人在此请求您的帮助。对于您的签名，我们深表感谢。如果可以的话，我们需要您的进一步帮助……”]]></description>
					<content:encoded><![CDATA[<p>
	为阻止Oracle收购Sun，在欧盟似乎已决定批准这项70亿美元的收购案之后，MySQL数据库创始人开始寻求中国和俄罗斯帮助。</p>
<p>
	在一封给中国 MySQL用户的邮件中写道 &ldquo;亲爱的拯救MySQL的中国签名支持者，欧盟可能无法拯救MySQL, 中国和俄罗斯可能是拯救MySQL的希望之所在。中国拥有强大、独立以及自信的反垄断主管机关，因此，我本人在此请求您的帮助。对于您的签名，我们深表感谢。如果可以的话，我们需要您的进一步帮助&hellip;&hellip;&rdquo;</p>
<p>
	<br />
	下面是具体的参与方法<br />
	点击这个链接并且填写自己的信息提交即可<br />
	<a href="http://helpmysql.org/cn/petition" target="_blank">http://helpmysql.org/cn/petition</a></p>
<p>
	&nbsp;</p>
<div class="header">
	<a href="http://helpmysql.org/cn"><img alt="" src="http://helpmysql.org/fwk/ml/10001094" /></a></div>
<p>
	&nbsp;</p>
<p>
	FAQ:</p>
<p>
	----------------------------------</p>
<p>
	<strong>我们还有多少时间？</strong></p>
<p>
	时间紧迫，但您仍然可以帮上忙。如果已经太晚（不论好还是坏），我们将立即停用请愿书，并在本网站每一页面上公布结果。</p>
<p>
	在我们通知您之前，请不要相信已经结束的任何说法。这些说法可能是试图破坏本次活动的某些人散布的。</p>
<p>
	本次活动网站于2009年12月28日启动。我们越早赢得大量支持者越好。关键的日期是2010年1月4日。那一天（明年的第一个工作日）我们计划 正式向监管者、其他政府机构、议会和记者提交请愿书。之后，我们将继续收集支持，直到程序结束，而且表示持续的支持也很重要。我们可能在2010年1月或 者可能2月份进行请愿书的多次提交。</p>
<p>
	<strong>活动为何是全球性的？</strong></p>
<p>
	甲骨文需要在全球所有主要市场取得审批。因此，我们将在世界不同地区提交请愿书。</p>
<p>
	一般而言，监管者会把数据库市场的地理范围界定为全球性的。只要想想MySQL，显然就明白了：人们可以在全球各地下载或获取MySQL，并在各地使用它。因此，您的签名支持甚至会到达您的国家以外的世界其他地方的监管者面前。</p>
<p>
	<strong>我们需要多少签名才能成功？</strong></p>
<p>
	没有特定限值。这不是事先就知道100,000签名者就能启动政治程序（根据某些法律）的请愿。这是有关MySQL用户的关注和希望达成令MySQL今后独立于甲骨文的真正解决方案（或者至少依赖程度更小）的表达。</p>
<p>
	这不仅仅是关于绝对数字的问题，而是如何能尽快签字，而且签字是否始终以较高速度增长的问题。您越快签字，越快让其他人知道就越好。</p>
<p>
	<strong>如何处理我的数据？我能相信你吗？</strong></p>
<p>
	我们知道如您支持本次活动那么您就信任我们，我们将证明我们是值得信赖的。</p>
<p>
	我们有明确的资料保密声明，请见<a href="http://helpmysql.org/cn/faq/link" page="" petition="" to="">请愿书页</a>，说明您的数据将只能用于提交请愿书给监管者、其他政府机关、议会和重要、声誉良好的新闻机构记者。如我们向您发送了有关本次活动的信息，您可点击取消链接，这样您将不会收到我们的任何其他电子邮件。</p>
<p>
	<strong>你们如何向监管者、议会和新闻机构提交请愿书？谁会看到请愿书？</strong></p>
<p>
	有时候请愿书是以打印文件的方式提交，以表明其数量庞大。但是，为了环保考虑，我们可能选择以电子格式提交大多数的请愿书。监管者、议会和重要、著 名的新闻媒体会收到它们，其中附带了不得以任何与本次活动无关的方式使用数据的明确要求，并且，新闻媒体必须签署接收上述要求的文件，并将不被允许从请愿 书中引用任何姓名和其他唯一或范围较窄的识别数据，除非他们从签字人处收到书面明示许可（包括电子邮件方式），允许在报道中提及。</p>
<p>
	处理本次案件的监管者将把请愿书放入甲骨文/太阳微电子案卷中。对于查看该卷宗有特殊的规定。例如，欧盟甲骨文律师当然会有权看到请愿书。因此，有必要让请愿书具有真正的震撼效果。</p>
<p>
	我们不要求请愿书中提供任何特殊的敏感信息，如您决定填写其中内容的，我们也不希望您在公共或私人评论字段中提供任何敏感信息。</p>
<p>
	<strong>如何能最有效地帮助请愿成功？</strong></p>
<p>
	显然最好的第一步就是您在请愿书上签字。</p>
<p>
	在<a href="http://helpmysql.org/cn/promote">帮助倡议</a> 部分，您可找到进一步说明和材料，以及在网站上设置的标语。</p>
<p>
	我们相信您知道其他专业的MySQL用户，并且有办法鼓励他们在请愿书上签字。</p>
<p>
	<strong>我需要现在亲自写信给欧盟吗？或者写信给本国的反垄断机构或议会，例如欧洲议会？</strong></p>
<p>
	我们认为本次活动将产生大量的回复，当然对于各个机构而言处理完整的请愿书更加容易一些。我们尽可能通过互联网进行号召，包括通过电子邮件，除非通过直接联系能够取得明显不同的良好效果。</p>
<p>
	如果您可以代表10名或以上员工规模的公司发言，并且MySQL对贵公司很重要，或者如果您可以代表100名或以上员工规模的公司发言，而且贵公司 把MySQL用于重大业务目的，请联系贵国反垄断机构，并表达您关于甲骨文收购MySQL计划的关注。如您需要任何帮助，请使用联系表向我们提问。</p>
]]></content:encoded>
				</item>			
							<item>
					<title>通过分区（Partition）提升MySQL性能</title>
					<link>http://www.phpv.net/html/1708.html</link>
					<comments>http://www.phpv.net/html/1708.html#comment</comments>
					<pubDate>Fri, 27 Nov 2009 10:49:16 +0800</pubDate>
					<dc:creator>抽烟的蚊子</dc:creator>
					<category><![CDATA[数据库技术]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1708.html</guid>
					<description><![CDATA[数据库分区是一种物理数据库设计技术，DBA和数据库建模人员对其相当熟悉。虽然分区技术可以实现很多效果，但其主要目的是为了在特定的SQL操作中减少数据读写的总量以缩减响应时间。]]></description>
					<content:encoded><![CDATA[什么是数据库分区？<br><br>数据库分区是一种物理数据库设计技术，DBA和数据库建模人员对其相当熟悉。虽然分区技术可以实现很多效果，但其主要目的是为了在特定的SQL操作中减少数据读写的总量以缩减响应时间。<br><br>分区主要有两种形式：//这里一定要注意行和列的概念（row是行，column是列）<br><br>1. 水平分区（Horizontal Partitioning）这种形式分区是对表的行进行分区，通过这样的方式不同分组里面的物理列分割的数据集得以组合，从而进行个体分割（单分区）或集体分割（1个或多个分区）。所有在表中定义的列在每个数据集中都能找到，所以表的特性依然得以保持。<br><br>举个简单例子：一个包含十年发票记录的表可以被分区为十个不同的分区，每个分区包含的是其中一年的记录。（朋奕注：这里具体使用的分区方式我们后面再说，可以先说一点，一定要通过某个属性列来分割，譬如这里使用的列就是年份）<br><br>2. 垂直分区（Vertical Partitioning） 这种分区方式一般来说是通过对表的垂直划分来减少目标表的宽度，使某些特定的列 被划分到特定的分区，每个分区都包含了其中的列所对应的行。<br><br>举个简单例子：一个包含了大text和BLOB列的表，这些text和BLOB列又不经常被访问，这时候就要把这些不经常使用的text和BLOB了划分到另一个分区，在保证它们数据相关性的同时还能提高访问速度。<br><br>在数据库供应商开始在他们的数据库引擎中建立分区（主要是水平分区）时，DBA和建模者必须设计好表的物理分区结构，不要保存冗余的数据（不同表中同时都包含父表中的数据）或相互联结成一个逻辑父对象（通常是视图）。这种做法会使水平分区的大部分功能失效，有时候也会对垂直分区产生影响。<br><br>在MySQL 5.1中进行分区<br><br>MySQL5.1中最激动人心的新特性应该就是对水平分区的支持了。这对MySQL的使用者来说确实是个好消息，而且她已经支持分区大部分模式：<br><br>Range（范围） – 这种模式允许DBA将数据划分不同范围。例如DBA可以将一个表通过年份划分成三个分区，80年代（1980’s）的数据，90年代（1990’s）的数据以及任何在2000年（包括2000年）后的数据。<br><br>Hash（哈希） – 这中模式允许DBA通过对表的一个或多个列的Hash Key进行计算，最后通过这个Hash码不同数值对应的数据区域进行分区，。例如DBA可以建立一个对表主键进行分区的表。<br><br>Key（键值） – 上面Hash模式的一种延伸，这里的Hash Key是MySQL系统产生的。<br><br>List（预定义列表） – 这种模式允许系统通过DBA定义的列表的值所对应的行数据进行分割。例如：DBA建立了一个横跨三个分区的表，分别根据2004年2005年和2006年值所对应的数据。<br><br>Composite（复合模式） - 很神秘吧，哈哈，其实是以上模式的组合使用而已，就不解释了。举例：在初始化已经进行了Range范围分区的表上，我们可以对其中一个分区再进行hash哈希分区。<br><br>分区带来的好处太多太多了，有多少？俺也不知道，自己猜去吧，要是觉得没有多少就别用，反正俺也不求你用。不过在这里俺强调两点好处：<br><br>性能的提升（Increased performance） - 在扫描操作中，如果MySQL的优化器知道哪个分区中才包含特定查询中需要的数据，它就能直接去扫描那些分区的数据，而不用浪费很多时间扫描不需要的地方了。需要举个例子？好啊，百万行的表划分为10个分区，每个分区就包含十万行数据，那么查询分区需要的时间仅仅是全表扫描的十分之一了，很明显的对比。同时对十万行的表建立索引的速度也会比百万行的快得多得多。如果你能把这些分区建立在不同的磁盘上，这时候的I/O读写速度就“不堪设想”（没用错词，真的太快了，理论上100倍的速度提升啊，这是多么快的响应速度啊，所以有点不堪设想了）了。<br><br>对数据管理的简化（Simplified data management） - 分区技术可以让DBA对数据的管理能力提升。通过优良的分区，DBA可以简化特定数据操作的执行方式。例如：DBA在对某些分区的内容进行删除的同时能保证余下的分区的数据完整性(这是跟对表的数据删除这种大动作做比较的)。<br><br>此外分区是由MySQL系统直接管理的，DBA不需要手工的去划分和维护。例如：这个例如没意思，不讲了，如果你是DBA，只要你划分了分区，以后你就不用管了就是了。<br><br>站在性能设计的观点上，俺们对以上的内容也是相当感兴趣滴。通过使用分区和对不同的SQL操作的匹配设计，数据库的性能一定能获得巨大提升。下面咱们一起用用这个MySQL 5.1的新功能看看。<br><br>下面所有的测试都在Dell Optiplex box with a Pentium 4 3.00GHz processor, 1GB of RAM机器上（炫耀啊……），Fedora Core 4和MySQL 5.1.6 alpha上运行通过。<br><br>如何进行实际分区<br><br>看看分区的实际效果吧。我们建立几个同样的MyISAM引擎的表，包含日期敏感的数据，但只对其中一个分区。分区的表（表名为part_tab）我们采用Range范围分区模式，通过年份进行分区：<br><br><br><br>&nbsp;&nbsp; 1. mysql&gt; CREATE TABLE part_tab<br>&nbsp;&nbsp; 2. -&gt; ( c1 int default NULL,<br>&nbsp;&nbsp; 3. -&gt; c2 varchar(30) default NULL,<br>&nbsp;&nbsp; 4. -&gt; c3 date default NULL<br>&nbsp;&nbsp; 5. -&gt;<br>&nbsp;&nbsp; 6. -&gt; ) engine=myisam<br>&nbsp;&nbsp; 7. -&gt; PARTITION BY RANGE (year(c3)) (PARTITION p0 VALUES LESS THAN (1995),<br>&nbsp;&nbsp; 8. -&gt; PARTITION p1 VALUES LESS THAN (1996) , PARTITION p2 VALUES LESS THAN (1997) ,<br>&nbsp;&nbsp; 9. -&gt; PARTITION p3 VALUES LESS THAN (1998) , PARTITION p4 VALUES LESS THAN (1999) ,<br>&nbsp; 10. -&gt; PARTITION p5 VALUES LESS THAN (2000) , PARTITION p6 VALUES LESS THAN (2001) ,<br>&nbsp; 11. -&gt; PARTITION p7 VALUES LESS THAN (2002) , PARTITION p8 VALUES LESS THAN (2003) ,<br>&nbsp; 12. -&gt; PARTITION p9 VALUES LESS THAN (2004) , PARTITION p10 VALUES LESS THAN (2010),<br>&nbsp; 13. -&gt; PARTITION p11 VALUES LESS THAN MAXVALUE );<br>&nbsp; 14. Query OK, 0 rows affected (0.00 sec) <br><br>注意到了这里的最后一行吗？这里把不属于前面年度划分的年份范围都包含了，这样才能保证数据不会出错，大家以后要记住啊，不然数据库无缘无故出错你就爽了。那下面我们建立没有分区的表（表名为no_part_tab）：<br><br><br>&nbsp;&nbsp; 1. mysql&gt; create table no_part_tab<br>&nbsp;&nbsp; 2. -&gt; (c1 int(11) default NULL,<br>&nbsp;&nbsp; 3. -&gt; c2 varchar(30) default NULL,<br>&nbsp;&nbsp; 4. -&gt; c3 date default NULL) engine=myisam;<br>&nbsp;&nbsp; 5. Query OK, 0 rows affected (0.02 sec) <br><br>下面咱写一个存储过程（感谢Peter Gulutzan给的代码，如果大家需要Peter Gulutzan的存储过程教程的中文翻译也可以跟我要，chenpengyi◎gmail.com），它能向咱刚才建立的已分区的表中平均的向每个分区插入共8百万条不同的数据。填满后，咱就给没分区的克隆表中插入相同的数据：<br><br><br>&nbsp;&nbsp; 1. mysql&gt; delimiter //<br>&nbsp;&nbsp; 2. mysql&gt; CREATE PROCEDURE load_part_tab()<br>&nbsp;&nbsp; 3. -&gt; begin<br>&nbsp;&nbsp; 4. -&gt; declare v int default 0;<br>&nbsp;&nbsp; 5. -&gt; while v &lt; 8000000<br>&nbsp;&nbsp; 6. -&gt; do<br>&nbsp;&nbsp; 7. -&gt; insert into part_tab<br>&nbsp;&nbsp; 8. -&gt; values (v,’testing partitions’,adddate(’1995-01-01′,(rand(v)*36520) mod 3652));<br>&nbsp;&nbsp; 9. -&gt; set v = v + 1;<br>&nbsp; 10. -&gt; end while;<br>&nbsp; 11. -&gt; end<br>&nbsp; 12. -&gt; //<br>&nbsp; 13. Query OK, 0 rows affected (0.00 sec)<br>&nbsp; 14. mysql&gt; delimiter ;<br>&nbsp; 15. mysql&gt; call load_part_tab();<br>&nbsp; 16. Query OK, 1 row affected (8 min 17.75 sec)<br>&nbsp; 17. mysql&gt; insert into no_part_tab select * from part_tab;<br>&nbsp; 18. Query OK, 8000000 rows affected (51.59 sec)<br>&nbsp; 19. Records: 8000000 Duplicates: 0 Warnings: 0 <br><br>表都准备好了。咱开始对这两表中的数据进行简单的范围查询吧。先分区了的，后没分区的，跟着有执行过程解析（MySQL Explain命令解析器），可以看到MySQL做了什么：<br><br><br><br>&nbsp;&nbsp; 1. mysql&gt; select count(*) from no_part_tab where<br>&nbsp;&nbsp; 2. -&gt; c3 &gt; date ‘1995-01-01′ and c3 &lt; date ‘1995-12-31′;<br>&nbsp;&nbsp; 3. +———-+<br>&nbsp;&nbsp; 4. | count(*) |<br>&nbsp;&nbsp; 5. +———-+<br>&nbsp;&nbsp; 6. | 795181 |<br>&nbsp;&nbsp; 7. +———-+<br>&nbsp;&nbsp; 8. 1 row in set (38.30 sec)<br>&nbsp;&nbsp; 9. mysql&gt; select count(*) from part_tab where<br>&nbsp; 10. -&gt; c3 &gt; date ‘1995-01-01′ and c3 &lt; date ‘1995-12-31′;<br>&nbsp; 11. +———-+<br>&nbsp; 12. | count(*) |<br>&nbsp; 13. +———-+<br>&nbsp; 14. | 795181 |<br>&nbsp; 15. +———-+<br>&nbsp; 16. 1 row in set (3.88 sec)<br>&nbsp; 17. mysql&gt; explain select count(*) from no_part_tab where<br>&nbsp; 18. -&gt; c3 &gt; date ‘1995-01-01′ and c3 &lt; date ‘1995-12-31′\G<br>&nbsp; 19. *************************** 1. row ***************************<br>&nbsp; 20. id: 1<br>&nbsp; 21. select_type: SIMPLE<br>&nbsp; 22. table: no_part_tab<br>&nbsp; 23. type: ALL<br>&nbsp; 24. possible_keys: NULL<br>&nbsp; 25. key: NULL<br>&nbsp; 26. key_len: NULL<br>&nbsp; 27. ref: NULL<br>&nbsp; 28. rows: 8000000<br>&nbsp; 29. Extra: Using where<br>&nbsp; 30. 1 row in set (0.00 sec)<br>&nbsp; 31. mysql&gt; explain partitions select count(*) from part_tab where<br>&nbsp; 32. -&gt; c3 &gt; date ‘1995-01-01′ and c3 &lt; date ‘1995-12-31′\G<br>&nbsp; 33. *************************** 1. row ***************************<br>&nbsp; 34. id: 1<br>&nbsp; 35. select_type: SIMPLE<br>&nbsp; 36. table: part_tab<br>&nbsp; 37. partitions: p1<br>&nbsp; 38. type: ALL<br>&nbsp; 39. possible_keys: NULL<br>&nbsp; 40. key: NULL<br>&nbsp; 41. key_len: NULL<br>&nbsp; 42. ref: NULL<br>&nbsp; 43. rows: 798458<br>&nbsp; 44. Extra: Using where<br>&nbsp; 45. 1 row in set (0.00 sec) <br><br>从上面结果可以容易看出，设计恰当表分区能比非分区的减少90％的响应时间。而命令解析Explain程序也告诉我们在对已分区的表的查询过程中仅对第一个分区进行了扫描，其他都跳过了。<br>哔厉吧拉，说阿说……反正就是这个分区功能对DBA很有用拉，特别对VLDB和需要快速反应的系统。<br><br>对Vertical Partitioning的一些看法<br><br>虽然MySQL 5.1自动实现了水平分区，但在设计数据库的时候不要轻视垂直分区。虽然要手工去实现垂直分区，但在特定场合下你会收益不少的。例如在前面建立的表中，VARCHAR字段是你平常很少引用的，那么对它进行垂直分区会不会提升速度呢？咱们看看测试结果：<br><br><br><br>&nbsp;&nbsp; 1. mysql&gt; desc part_tab;<br>&nbsp;&nbsp; 2. +——-+————-+——+—–+———+——-+<br>&nbsp;&nbsp; 3. | Field | Type | Null | Key | Default | Extra |<br>&nbsp;&nbsp; 4. +——-+————-+——+—–+———+——-+<br>&nbsp;&nbsp; 5. | c1 | int(11) | YES | | NULL | |<br>&nbsp;&nbsp; 6. | c2 | varchar(30) | YES | | NULL | |<br>&nbsp;&nbsp; 7. | c3 | date | YES | | NULL | |<br>&nbsp;&nbsp; 8. +——-+————-+——+—–+———+——-+<br>&nbsp;&nbsp; 9. 3 rows in set (0.03 sec)<br>&nbsp; 10. mysql&gt; alter table part_tab drop column c2;<br>&nbsp; 11. Query OK, 8000000 rows affected (42.20 sec)<br>&nbsp; 12. Records: 8000000 Duplicates: 0 Warnings: 0<br>&nbsp; 13. mysql&gt; desc part_tab;<br>&nbsp; 14. +——-+———+——+—–+———+——-+<br>&nbsp; 15. | Field | Type | Null | Key | Default | Extra |<br>&nbsp; 16. +——-+———+——+—–+———+——-+<br>&nbsp; 17. | c1 | int(11) | YES | | NULL | |<br>&nbsp; 18. | c3 | date | YES | | NULL | |<br>&nbsp; 19. +——-+———+——+—–+———+——-+<br>&nbsp; 20. 2 rows in set (0.00 sec)<br>&nbsp; 21. mysql&gt; select count(*) from part_tab where<br>&nbsp; 22. -&gt; c3 &gt; date ‘1995-01-01′ and c3 &lt; date ‘1995-12-31′;<br>&nbsp; 23. +———-+<br>&nbsp; 24. | count(*) |<br>&nbsp; 25. +———-+<br>&nbsp; 26. | 795181 |<br>&nbsp; 27. +———-+<br>&nbsp; 28. 1 row in set (0.34 sec) <br><br>在设计上去掉了VARCHAR字段后，不止是你，俺也发现查询响应速度上获得了另一个90％的时间节省。所以大家在设计表的时候，一定要考虑，表中的字段是否真正关联，又是否在你的查询中有用？<br><br>补充说明<br><br>这么简单的文章肯定不能说全MySQL 5.1 分区机制的所有好处和要点（虽然对自己写文章水平很有信心），下面就说几个感兴趣的：<br><br>◆支持所有存储引擎(MyISAM, Archive, InnoDB, 等等)<br><br>◆ 对分区的表支持索引，包括本地索引local indexes，对其进行的是一对一的视图镜像，假设一个表有十个分区，那么其本地索引也包含十个分区。<br><br>◆关于分区的元数据Metadata的表可以在INFORMATION_SCHEMA数据库中找到，表名为PARTITIONS。<br><br>◆All SHOW 命令支持返回分区表以及元数据的索引。<br><br>◆对其操作的命令和实现的维护功能有（比对全表的操作还多）：<br><br><br><br>&nbsp;&nbsp; 1. o ADD PARTITION<br>&nbsp;&nbsp; 2. o DROP PARTITION<br>&nbsp;&nbsp; 3. o COALESCE PARTITION<br>&nbsp;&nbsp; 4. o REORGANIZE PARTITION<br>&nbsp;&nbsp; 5. o ANALYZE PARTITION<br>&nbsp;&nbsp; 6. o CHECK PARTITION<br>&nbsp;&nbsp; 7. o OPTIMIZE PARTITION<br>&nbsp;&nbsp; 8. o REBUILD PARTITION<br>&nbsp;&nbsp; 9. o REPAIR PARTITION <br><br>站在性能主导的观点上来说，MySQL 5.1的分区功能能给数据性能带来巨大的提升的同时减轻DBA的管理负担，如果分区合理的话。如果需要更多的资料可以去 http://dev.mysql.com/doc/refman/5.1/en/partitioning.html或 http://forums.mysql.com/list.php?106获得相关资料。<br><br>]]></content:encoded>
				</item>			
							<item>
					<title>PHP里模拟$_PUT</title>
					<link>http://www.phpv.net/html/1705.html</link>
					<comments>http://www.phpv.net/html/1705.html#comment</comments>
					<pubDate>Tue, 10 Nov 2009 10:30:02 +0800</pubDate>
					<dc:creator>抽烟的蚊子</dc:creator>
					<category><![CDATA[PHP技术文档]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1705.html</guid>
					<description><![CDATA[PHP里有$_GET，$_POST，但是没有$_PUT  本文介绍使用php://input特性来模拟$_PUT]]></description>
					<content:encoded><![CDATA[PHP里有$_GET，$_POST，但是没有$_PUT，所以如果需要使用它的话，则你不得不自己模拟一下：<br><br>&nbsp;$_PUT = array();<br>if ('PUT' == $_SERVER['REQUEST_METHOD']) {<br>&nbsp;&nbsp;&nbsp;&nbsp; parse_str(file_get_contents('php://input'), $_PUT);<br>&nbsp;}<br><br>通过php://input得到的数据是raw data，所以需要用parse_str解析一下。<br><br>不过需要说明的是，当表单是enctype="multipart/form-data"类型的时候（就是上传文件那种类型），这种方法是无效的（此时 php://input为空），一旦PHP发现请求的Content-Type是multipart/form-data，就会无条件的代你处理表单数据，然后保存到$_FILES里，此时无法得到raw data，只能用一些偏门方法<br><br>以apache为例，修改httpd.conf（为了使用RequestHeader语法，请先激活header模块）：<br><br>&lt;Location "/demo.php"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; RequestHeader set Content-Type foobar<br>&nbsp;&lt;/Location&gt;<br><br>通过重置Content-Type请求头为foobar（只要不是multipart/form-data即可），此时php://input就有数据了，不过原本应有的$_FILES数据却不存在了，所以基本上只有演示上的意义，如果想得到raw data，只能自己根据数据生成，在PEAR里有类似的实现：HTTP_Request2_MultipartBody。<br><br>浏览器一般只允许使用GET/POST方法，虽然可以通过JS来发送PUT方法，但是还得编写代码，相对而言，使用命令行下的CURL命令则显得方便很多，在开发测试时很有用，所以学习一下还是必要的：<br><br>curl -X PUT http://www.domain.com/demo.php -d "id=1" -d "title=a"<br><br>这样就会通过PUT方法发送id, title数据，测试时demo.php的代码就类似上面的php://input。 <br>]]></content:encoded>
				</item>			
							<item>
					<title>HR与程序员是怎么读你的求职简历的</title>
					<link>http://www.phpv.net/html/1704.html</link>
					<comments>http://www.phpv.net/html/1704.html#comment</comments>
					<pubDate>Tue, 10 Nov 2009 10:18:26 +0800</pubDate>
					<dc:creator>admin</dc:creator>
					<category><![CDATA[其它杂谈]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1704.html</guid>
					<description><![CDATA[程序员是这样阅读简历的
曾经因为好玩而写过操作系统或编译器。+15
为开源软件贡献过代码。+11分
上学的时候曾经写过操作系统或编译器。+9分
在技能中，把Visual Basic列在第一的位置。-10分
简历中的缩进同时使用了空格和Tab键。-15分
]]></description>
					<content:encoded><![CDATA[<h4>人事部门是这样阅读简历的</h4><br><br>
<ul><li>（+15分）如果简历中说到了和工作职位相符的技能超过5次以上。</li><li>（+8分）如果简历中说到了和工作职位相符的技能3次到5次。</li><li>（+4分）如果简历中说到了和工作职位相符的技能1次到2次。</li><li>（+4分）Cover Letter（“求职信”或“自荐信”）提到了招聘人员。</li><li>（+2分）简历中有Cover Letter（求职信）。</li><li>（-10分）没有提到和职位描述相关的技能。</li><li>（-15分）没有受过大专教育。</li></ul>
<h4><br></h4><h4>程序员是这样阅读简历的</h4><br>
<ul><li>（+15分）曾经因为好玩而写过操作系统或编译器。</li><li>（+12分）简历被Latex编译过。</li><li>（+11分）为开源软件贡献过代码。</li><li>（+9分）上学的时候曾经写过操作系统或编译器。</li><li>（+8分）有一个BLOG分享技术知识。</li><li>（+8分）编程/机器人/工程俱乐部主席。</li><li>（+7分）编程/机器人/工程竞赛参与者。</li><li>（+7分）在Google和Microsoft实习过。</li><li>（+6分）使用动态语言（Python/Perl/Ruby）写过非试验性的程序。</li><li>（+5分）知道3种或多于3种的编程语言。</li><li>（+5分）之前的工作和目前的职位有很相似的经验。</li><li>（+4分）有过实习经验。</li><li>（+4分）自己创过业开过公司。</li><li>（+4分）有一个通过Rail, PHP或ASP.NET的个人主页。</li><li>（+3分）有一个自己域名的邮件地址。</li><li>（+3分）改过一些由动态语言（Python/Perl/Ruby）写的程序。</li><li>（+2分）有一个个人主页。</li><li>（+1分）高学历，学习成绩优秀，等。</li><li>（+0分）有奖学金。</li><li>（+0分）在快餐店工作过。</li><li>（-0.5分）Fackbook上有一张看上去喝醉了的照片。</li><li>（-1分）有博士头衔。</li><li>（-2分）有一个一般的求职信。</li><li style="color: rgb(255, 0, 0);">（-2分）在简历中说自己懂Word/Excel。</li><li>（-2分）在简历中有拼写和语法错误。</li><li>（-3分）简历的字体太小。</li><li>（-4分）所有的编程经验只是在学校中。</li><li>（-4分）只知道一门编程语言。</li><li>（-6分）简历有三页以上。</li><li>（-6分）简历中有一些无关的东西。</li><li>（-7分）得到过一些课程的认证。</li><li>（-8分）相关专业课程很低的成绩。</li><li>（-10分）在技能中，把Visual Basic列在第一的位置。</li><li>（-12分）在Facebook中，有过光膀子的照片。</li><li style="color: rgb(255, 0, 0);">（-15分）简历中的缩进同时使用了空格和Tab键。</li></ul>
<p><br></p><p>我个人觉得其中的很多东西真是说出了程序员的那种特性。</p><p>配图<br>------------------------------------------------<br></p><p>下面这个图片来源国外，是一个关于程序员面试时的简历，被人事部门和程序员本身评审的角度不同的图片。当然，这是一个从国外面试的视角制作的图片，不过，可以看出，其中很多东西都是和国内是相同的。让我们通过这个图片也来了解一下自身吧。
</p><p align="center"><a href="http://coolshell.cn/wp-content/uploads/2009/11/resume_comic.png" target="_blank"><img title="程序员怎样阅读简历" src="http://www.phpv.net/uploadfile/month_200911/local_xKbmGM1lkg.png" alt="程序员怎样阅读简历（点击看大图）" height="1024" width="552"></a></p>



]]></content:encoded>
				</item>			
							<item>
					<title>谈PHP 闭包特性在实际应用中的问题</title>
					<link>http://www.phpv.net/html/1703.html</link>
					<comments>http://www.phpv.net/html/1703.html#comment</comments>
					<pubDate>Tue, 13 Oct 2009 10:15:52 +0800</pubDate>
					<dc:creator>抽烟的蚊子</dc:creator>
					<category><![CDATA[PHP5研究[新]]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1703.html</guid>
					<description><![CDATA[PHP5.3 新版本跟随了很多新特性， 其中比较惹眼的特性之一就是支持了闭包。那么以后，我们也可以和那帮写 Ruby、Javascript 等等“高科技语言”的家伙们一样，写出非常酷的代码吗？呃，其实大部分情况下是可以的，而有些方面还是令人非常的困扰]]></description>
					<content:encoded><![CDATA[<p>原文链接： <a href="http://justafewlines.com/2009/10/whats-wrong-with-php-closures/" title="http://justafewlines.com/2009/10/whats-wrong-with-php-closures/">http://justafewlines.com/2009/10/whats-wrong-with-php-closures/</a></p>

<p><a href="http://php.net/releases/5_3_0.php" title="http://php.net/releases/5_3_0.php">PHP5.3 新版本跟随了很多新特性</a>， 其中比较惹眼的特性之一就是支持了闭包。那么以后，我们也可以和那帮写 Ruby、Javascript 等等“高科技语言”的家伙们一样，写出非常酷的代码吗？呃，其实大部分情况下是可以的，而有些方面还是令人非常的困扰，下面慢慢道来。</p>

<p>很多语言的都提供了非常优雅和漂亮的操作数组的方法。在下面的例子中，会使用 PHP5.3 以及其他语言提供的闭包功能，用于展示如何“客观的”操作迭代数组。</p>

<p>译注：原文作者比较火星，我不了解 Groovy 以及 Scala 语言，所以这里我加上 Javascript 的实现。</p>

<p>在开始之前先说明下，本例子仅仅是阐明观点，并没有考虑性能等其他方面的因素。</p>

<h2>“货比三家”</h2><p>用个简单的例子开始，有下面个数组：</p>

<pre>$nums = array(10, 20, 30, 40);</pre><p>需要找出数组中大于 15 的项。那么，不考虑闭包的情况下，我们或许会这样写：</p>

<pre>$res = array();<br>foreach ($nums as $n) {<br>    if ($n &gt; 15) {<br>        $res[] = $n;<br>    }<br>}</pre><p>如果语言本身有闭包支持的，那么或许会这样写（Groovy 语言）</p>

<pre>def res = nums.findAll { it &gt; 15 }</pre><p>或者使用 Scala 语言</p>

<pre>val res = nums filter (_ &gt; 15)</pre><p>译注：Javascript 1.6 的话会是如下</p>

<pre>var res = nums.filter(function(c){return c &gt; 15});</pre><p>因为循环操作已被抽象起来，所以可以看到 Groovy 、Scala （以及 Javascript） 都很漂亮得用一行就可以搞定。</p>

<p>当然，如果使用 PHP5.3 的闭包，也可以做到</p>

<pre>$res = array_filter($nums, function($v) { return $v &gt; 15; });</pre><p>PHP 在这方面使用了比 Scala 更多的字符，但对比先前的例子，它更简短并且能更好得阅读。</p>

<p>顺便说下，上面的 PHP 代码实际上是使用了 Lambda 解析式，并不是个真正的闭包，这个 并不是我们目前关注的重点。详细阐述 PHP 闭包以及 Lambda 解析式的资料，可以<a href="http://wiki.php.net/rfc/closures" title="http://wiki.php.net/rfc/closures">参考这里</a>。</p>

<p>目前看来感觉都还不错，那么我们再的题目增加点难度：找到所有大于 15 的项， 然后乘以 2 再加上作用域中的的某个变量值以后再返回。</p>

<p>Groovy 的实现：</p>

<pre>def x = 1<br>def res = nums .findAll { it &gt; 15 } .collect { it * 2 + x }</pre><p>Scala 的实现：</p>

<pre>val x = 1<br>val res = nums filter (_ &gt; 15) map (_ * 2 + x)</pre><p>译注，Javascript 的实现：</p>

<pre>var i = 1;<br>var res = nums.filter(function(c){return c &gt; 15}).map(function(c){return c * 2 + i});</pre><p>以及 PHP：</p>

<pre>$x = 1;<br>$res = array_map(<br>    function($v) use ($x) { return $v * 2 + $x; },<br>    array_filter(<br>        $nums,<br>        function($v) { return $v &gt; 15; })<br>);</pre><p>光从代码量方面，现在看起来 PHP 与其他语言有出入了。先抛开代码字面上本身 的审美不谈，上面的 PHP 代码还有个额外的问题。</p>

<p>例如，如果需要使用数组的键而非值作比较，怎么办？是的，上面的代码就办不到了。同时，从语法角度上说，上面的代码非常难以阅读。</p>

<p>返璞归真，这时还是得返回老土的思路去解决问题：</p>

<pre>$x = 1;<br>$res = array();<br>foreach ($nums as $n) {<br>    if ($n &gt; 15) {<br>        $res[] = $n * 2 + $x;<br>    }<br>}</pre><p>呼，这样看起来又很清楚了。但这个时候你或许又会迷惑了：“那还瞎折腾啥，这不就是个数组操作吗？”。</p>

<p>是的，好戏还在后头。这个时候该让 PHP 的某些高级特性出场，来搞定这看似有自残倾向 的“无聊问题”。</p>

<h2>ArrayObject – 对数组的封装</h2><p>PHP 有个称作 <a href="http://www.gracecode.com/archives/2965/" title="http://www.gracecode.com/archives/2965/">SPL 的标准库</a>，其中包含了个叫做 <a href="http://php.net/manual/en/class.arrayobject.php" title="http://php.net/manual/en/class.arrayobject.php">ArrayObject</a> 的类，它能提供“像数组一 样操作类”的功能，例如</p>

<pre>$res = new ArrayObject(array(10, 20, 30, 40));<br>foreach ($res as $v) {<br>    echo "$vn";<br>}</pre><p>ArrayObject 是个内置的类，所以你可以像其他类类操作一样封装它。</p>

<h2>Arr - 包上糖衣</h2><p>既然我们已经有了 ArrayObject 以及闭包这些特性，我们就可以开始尝试封装它：</p>

<pre>class Arr extends ArrayObject<br>{<br>    static function make($array)<br>    {<br>        return new self($array);<br>    }<br><br>    function map($func)<br>    {<br>        $res = new self();<br>        foreach ($this as $k =&gt; $v) {<br>            $res[$k] = $func($k, $v);<br>        }<br>        return $res;<br>    }<br><br>    function filter($func)<br>    {<br>        $res = new self();<br>        foreach ($this as $k =&gt; $v) {<br>            if ($func($k, $v)) {<br>                $res[$k] = $v;<br>            }<br>        }<br>        return $res;<br>    }<br>}</pre><p>好了，万事俱备。下面重写的 PHP 代码就可以解决上面提到的问题，并且看起来语法上“差 不多”了：</p>

<pre>$res = Arr::make($nums)<br>    -&gt;filter(function($k, $v) { return $v &gt; 15; })<br>    -&gt;map(function($k, $v) { return $v * 2; });</pre><p>上面的代码与传统方式有何不同呢？首先，它们可以递归并形成作用链式的调用，因此可以 添加更多的类似操作。</p>

<p>同时，可以通过回调的两个参数分别操作数组的键以及值其项 - $k 对应键以及 $v 对应值 。这使得我们可以在闭包中使用键值，这在传统的 PHP 函数 array_fliter 中是无法实现的。</p>

<p>另外个带来的额外好处就是更加一致 API 调用。使用传统的 PHP 函数操作，它们有可能第一个参数是个闭包，或者是个数组，抑或是多个数组…总之谁知道呢？</p>

<p><a href="http://justafewlines.com/wp-content/uploads/2009/10/closures-arr-example.zip" title="http://justafewlines.com/wp-content/uploads/2009/10/closures-arr-example.zip">这里是 Arr 类的完整源代码</a>，还包含了其他有用的函数（类似 reduce 以及 walk），其实它 们的实现其实方式和代码类似。</p>

<h2>博弈</h2><p>这个问题其实很难回答 - 这需要根据代码的上下文以及程序员自身等众多因素决定。其实 ，当我第一眼看见 PHP 的闭包实现时，我感觉似乎回到了那很久以前的 Java 时期，当时 我在开始使用<a href="http://www.roseindia.net/javatutorials/anonymous_innerclassestutorial.shtml" title="http://www.roseindia.net/javatutorials/anonymous_innerclassestutorial.shtml">匿名内置类（anonymous inner classes）</a>来实现闭包。当然，这虽然可以做到， 但看起来实在是些画蛇添足。PHP 闭包本身是没错，只是它的实现以及语法让我感到非常的困惑。</p>

<p>其他具有闭包特性的语言，它们可以非常方便的调用闭包并同时具有优雅的语法。在上面的例子 中，在 Scala 中使用传统的循环也可以工作，但你会这样写吗？而从另个方面，那么有人 说上面这个题目使用 PHP 的闭包也可以实现，但一般情况下你会这样写吗？</p>

<p>可以确定，PHP 闭包在些情况下可以成为锐利的军刀（例如延时执行以及资源调用方面）， 但在传统的迭代以及数组操作面前就显得有些为难。不要气馁不管怎么样， 返璞归真编写具有兼容性的、清爽的代码以及 API 是最重要的。</p>

<h2>结束语</h2><p>像所有后来加上的语法特性一样（记得当年 Java 的 Generics 特性不？以及前几年的 PHP OOP
特性），它们都需要时间磨合以及最终稳定下来。随着 PHP5.3 甚至将来的 PHP6
逐渐普及，越来越多的技巧和特性相信在不远的将来逐渐的被聪明的程序员挖掘出来。</p>

<p>回到最初文章开头那个题目，对比</p>

<pre>$res = Arr::make($nums)<br>    -&gt;filter(function($k, $v) { return $v &gt; 15; })<br>    -&gt;map(function($k, $v) { return $v * 2; });</pre><p>以及</p>

<pre>val res = nums filter (_ &gt; 15) map (_ * 2)</pre><p>两者之间的区别。归根结底它们仅是语法而已，本质上都是殊途同归解决了同个问题。程序 语言的应用特性不同，自然孰优孰劣也就无从比较。</p>

<p>最后，<a href="http://justafewlines.com/wp-content/uploads/2009/10/closures-arr-example.zip" title="http://justafewlines.com/wp-content/uploads/2009/10/closures-arr-example.zip">这里有此篇文章的代码示例</a>， 相信可以找到更多如何使用 PHP 进行函数式迭代（当然不仅仅是这些）的心得。</p>

<p><tt>-- Split --</tt></p>

<h2>不靠谱之博主心得</h2><p>坦白讲，虽然在 PHP5.0 之前就了解过提出的新增闭包等功能，但在看到 PHP5.3 提供的闭 包以及 Lambda 功能后，与原本心理期待的还是有些出入。</p>

<p>甚至相对于熟悉的 JavaScript，PHP 的闭包在我看来，像是“别的语言都有了，所以我也要有” 的这种心态下的产物。</p>

<p>但正如上文中所言，相比 JavaScript 等其他动态语言，PHP 出于自身的应用以及实现的哲学 出发，与其他开发语言不尽相同。</p>

<p>因此在某些特性的调用方式、实现方法也会不一样，这难免会让熟悉另外具有类似功能的语言 的人感到的不适应。</p>

<p>从 PHP5.3 推出至今，还不到半年的时间，相比 JavaScript 等这些早已具有闭包等特性的 动态语言相比，自然是显得非常稚嫩。</p>

<p>同时，广大的开发者对于 PHP5.3 提供的包括闭包在内的新特性还在持观望态度。PHP 的闭包特性目前还是存在于实验室中，其应用于实际开发如要突破的不仅仅是语言特性 ，还要经过效率、安全性等方面的考验。</p>

<p>但相信，如原文作者所言，随着 PHP 版本的推进，PHP 的闭包应用场合会越来越频繁。像 当年 PHP4 转换到 PHP5 一样，对语言新特性的适应，其实是种痛并快乐着的过程。</p>

]]></content:encoded>
				</item>			
							<item>
					<title>JavaScript可否多线程? 深入理解JavaScript定时机制</title>
					<link>http://www.phpv.net/html/1700.html</link>
					<comments>http://www.phpv.net/html/1700.html#comment</comments>
					<pubDate>Sun, 27 Sep 2009 11:41:00 +0800</pubDate>
					<dc:creator>admin</dc:creator>
					<category><![CDATA[前端交互]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1700.html</guid>
					<description><![CDATA[浏览器中的JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,这些任务可以源自 JavaScript引擎当前执行的代码块,如调用setTimeout添加一个任务,也可来自浏览器内核的其它线程,如界面元素鼠标点击事件,定时触发器时间到达通知,异步请求状态变更通知等.从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线程关系,这些任务得进行排队,一个接着一个被引擎处理.]]></description>
					<content:encoded><![CDATA[<p>JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如</p>
<blockquote><p>
setTimeout( function(){ alert(’你好!’); } , 0);<br>
setInterval( callbackFunction , 100);
</p></blockquote>
<p>认为setTimeout中的问候方法会立即被执行,因为这并不是凭空而说,而是JavaScript API文档明确定义第二个参数意义为隔多少毫秒后,回调方法就会被执行. 这里设成0毫秒,理所当然就立即被执行了.<br>
同理对setInterval的callbackFunction方法每间隔100毫秒就立即被执行深信不疑!</p>
<p>但随着JavaScript应用开发经验不断的增加和丰富,有一天你发现了一段怪异的代码而百思不得其解:</p>
<blockquote><p>
 div.onclick = function(){<br>
    setTimeout( function(){document.getElementById(’inputField’).focus();}, 0);<br>
 };
</p></blockquote>
<p>既然是0毫秒后执行,那么还用setTimeout干什么, 此刻, 坚定的信念已开始动摇.<br>
<span id="more-341"></span><br>
直到最后某一天 , 你不小心写了一段糟糕的代码:</p>
<blockquote><p>
setTimeout( function(){ while(true){} } , 100);<br>
setTimeout( function(){ alert(’你好!’); } , 200);<br>
setInterval( callbackFunction , 200);
</p></blockquote>
<p>第一行代码进入了死循环,但不久你就会发现,第二,第三行并不是预料中的事情,alert问候未见出现,callbacKFunction也杳无音讯!</p>
<p>这时你彻底迷惘了,这种情景是难以接受的,因为改变长久以来既定的认知去接受新思想的过程是痛苦的,但情事实摆在眼前,对JavaScript真理的探求并不会因为痛苦而停止,下面让我们来展开JavaScript线程和定时器探索之旅!</p>
<p><strong>拔开云雾见月明</strong></p>
<p>出现上面所有误区的最主要一个原因是:潜意识中认为,JavaScript引擎有多个线程在执行,JavaScript的定时器回调函数是异步执行的.</p>
<p>而事实上的,JavaScript使用了障眼法,在多数时候骗过了我们的眼睛,这里背光得澄清一个事实:</p>
<blockquote><p>
<strong>JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序.</strong>
</p></blockquote>
<p>JavaScript引擎用单线程运行也是有意义的,单线程不必理会线程同步这些复杂的问题,问题得到简化.</p>
<p>那么单线程的JavaScript引擎是怎么配合浏览器内核处理这些定时器和响应浏览器事件的呢?<br>
下面结合浏览器内核处理方式简单说明.</p>
<p>浏览器内核实现允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步.假如某一浏览器内核的实现至少有三个常驻线
程:javascript引擎线程,界面渲染线程,浏览器事件触发线程,除些以外,也有一些执行完就终止的线程,如Http请求线程,这些异步线程都会产
生不同的异步事件,下面通过一个图来阐明单线程的JavaScript引擎与另外那些线程是怎样互动通信的.虽然每个浏览器内核实现细节不同,但这其中的
调用原理都是大同小异.</p>
<p><a href="http://www.phpv.net/uploadfile/month_200909/local_iq9hPSQMfQ.jpg" target="_blank"><img alt="" src="http://www.phpv.net/uploadfile/month_200909/local_9CBIg5d80M.jpg" align="" border="0px"><br></a></p>
<p>由图可看出,浏览器中的JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,这些任务可以源自
JavaScript引擎当前执行的代码块,如调用setTimeout添加一个任务,也可来自浏览器内核的其它线程,如界面元素鼠标点击事件,定时触发
器时间到达通知,异步请求状态变更通知等.从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线
程关系,这些任务得进行排队,一个接着一个被引擎处理.</p>
<p>上图t1-t2..tn表示不同的时间点,tn下面对应的小方块代表该时间点的任务,假设现在是t1时刻,引擎运行在t1对应的任务方块代码内,在这个时间点内,我们来描述一下浏览器内核其它线程的状态.</p>
<p><strong>t1时刻:</strong></p>
<p>GUI渲染线程:</p>
<p>该线程负责渲染浏览器界面HTML元素,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行.本文虽然重
点解释JavaScript定时机制,但这时有必要说说渲染线程,因为该线程与JavaScript引擎线程是互斥的,这容易理解,因为
JavaScript脚本是可操纵DOM元素,在修改这些元素属性同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致了.</p>
<blockquote><p>
<strong>在JavaScript引擎运行脚本期间,浏览器渲染线程都是处于挂起状态的,也就是说被”冻结”了.</strong>
</p></blockquote>
<p>所以,在脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出来,这些操作将保存在一个队列中,待JavaScript引擎空闲时才有机会渲染出来.</p>
<p>GUI事件触发线程:</p>
<p>JavaScript脚本的执行不影响html元素事件的触发,在t1时间段内,首先是用户点击了一个鼠标键,点击被浏览器事件触发线程捕捉后形成
一个鼠标点击事件,由图可知,对于JavaScript引擎线程来说,这事件是由其它线程异步传到任务队列尾的,由于引擎正在处理t1时的任务,这个鼠标
点击事件正在等待处理.</p>
<p>定时触发线程:</p>
<p>注意这里的浏览器模型定时计数器并不是由JavaScript引擎计数的,因为JavaScript引擎是单线程的,如果处于阻塞线程状态就计不了时,它必须依赖外部来计时并触发定时,所以队列中的定时事件也是异步事件.</p>
<p>由图可知,在这t1的时间段内,继鼠标点击事件触发后,先前已设置的setTimeout定时也到达了,此刻对JavaScript引擎来说,定时触发线程产生了一个异步定时事件并放到任务队列中, 该事件被排到点击事件回调之后,等待处理.<br>
同理, 还是在t1时间段内,接下来某个setInterval定时器也被添加了,由于是间隔定时,在t1段内连续被触发了两次,这两个事件被排到队尾等待处理.</p>
<p>可见,假如时间段t1非常长,远大于setInterval的定时间隔,那么定时触发线程就会源源不断的产生异步定时事件并放到任务队列尾而不管它
们是否已被处理,但一旦t1和最先的定时事件前面的任务已处理完,这些排列中的定时事件就依次不间断的被执行,这是因为,对于JavaScript引擎来
说,在处理队列中的各任务处理方式都是一样的,只是处理的次序不同而已.</p>
<p>t1过后,也就是说当前处理的任务已返回,JavaScript引擎会检查任务队列,发现当前队列非空,就取出t2下面对应的任务执行,其它时间依此类推,由此看来:</p>
<blockquote><p>
<strong>如果队列非空,引擎就从队列头取出一个任务,直到该任务处理完,即返回后引擎接着运行下一个任务,在任务没返回前队列中的其它任务是没法被执行的.</strong>
</p></blockquote>
<p>相信您现在已经很清楚JavaScript是否可多线程,也了解理解JavaScript定时器运行机制了,下面我们来对一些案例进行分析:</p>
<p><strong>案例1:setTimeout与setInterval</strong></p>
<pre>setTimeout(function(){<br>   /* 代码块... */<br>   setTimeout(arguments.callee, 10);<br>}, 10);<br><br>setInterval(function(){<br>   /*代码块... */<br> }, 10);<br></pre>
<p>这两段代码看一起效果一样,其实非也,第一段中回调函数内的setTimeout是JavaScript引擎执行后再设置新的setTimeout
定时, 假定上一个回调处理完到下一个回调开始处理为一个时间间隔,理论两个setTimeout回调执行时间间隔&gt;=10ms
.第二段自setInterval设置定时后,定时触发线程就会源源不断的每隔十秒产生异步定时事件并放到任务队列尾,理论上两个setInterval
回调执行时间间隔&lt;=10.</p>
<p><strong>案例2:ajax异步请求是否真的异步?</strong></p>
<p>很多同学朋友搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?<br>
其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求(参见上图),当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到
JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行
onreadystatechange所设置的函数.</p>

]]></content:encoded>
				</item>			
							<item>
					<title>PHP文件上传源码分析(RFC1867)</title>
					<link>http://www.phpv.net/html/1699.html</link>
					<comments>http://www.phpv.net/html/1699.html#comment</comments>
					<pubDate>Sun, 27 Sep 2009 11:36:01 +0800</pubDate>
					<dc:creator>admin</dc:creator>
					<category><![CDATA[PHP技术文档]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1699.html</guid>
					<description><![CDATA[文件上传,一般分为俩种方式FTP和HTTP, 对于我们的互联网应用来说: FTP上传虽然传输稳定, 但是易用性和安全性都是个问题.而基于HTTP的上传,相对来说易用性和安全性上就比FTP要增强了很多. 可以应用的上传方式有PUT, WEBDAV, 和RFC1867三种, 本文将分析在PHP中,是如何基于RFC1867实现文件上传的. ]]></description>
					<content:encoded><![CDATA[<p>
文件上传,一般分为俩种方式FTP和HTTP, 对于我们的互联网应用来说: FTP上传虽然传输稳定, 但是易用性和安全性都是个问题.
你总不至于在用户要上传头像的时候告诉用户”请打开FTP客户端,上传文件到http://www.laruence.com/uploads/中,
并以2dk433423l.jpg命名”吧? </p>
<p>而基于HTTP的上传,相对来说易用性和安全性上就比FTP要增强了很多. 可以应用的上传方式有PUT, WEBDAV, 和RFC1867三种, 本文将分析在PHP中,是如何基于RFC1867实现文件上传的.
</p>
<h3>RFC1867</h3>
<p>
RCF1867是Form-based File Upload in HTML标准协议, RFC1867标准对HTML做出了两处修改：<br>
　</p>
<pre>1 为input元素的type属性增加了一个file选项。<br>2 input标记可以具有accept属性，该属性能够指定可被上传的文件类型或文件格式列表。<br></pre>
<p>　　<br>
	另外，本标准还定义了一种新的mime类型：multipart/form-data，以及当处理一个带有enctype=”multipart/form-data” 并且/或含有&lt;input type=”file”&gt;的标记的表单时所应该采取的行为。<br>
　　<br>
	举例来说，当HTML想让用户能够上传一个或更多的文件时，他可以这么写：</p>
<pre>&lt;form enctype="multipart/form-data" action="upload.php" method=post&gt;<br>选择文件:<br>&lt;input name="userfile" type="file"&gt;<br>文件描述:<br>&lt;input name="description" type="text"&gt;<br>&lt;input type="submit" value="上传"&gt;<br>&lt;/form&gt;<br></pre>
<p> 这个表单, 大家一定不陌生, 而对于PHP来说, 它自己另外定义了一个默认表单元素MAX_FILE_SIZE,
用户可以通过这个隐藏的表单元素来建议PHP最多只容许上传文件的大小, 比如对于上面的例子,
我们希望用户上传的文件不能大于5000(5k)字节, 那么可以如下写:</p>
<pre>&lt;form enctype="multipart/form-data" action="upload.php" method=post&gt;<br>&lt;input type="hidden" value="5000" name="MAX_FILE_SIZE"&gt; &lt;!--文件大小--&gt;<br>选择文件:<br>&lt;input name="userfile" type="file"&gt;<br>文件描述:<br>&lt;input name="description" type="text"&gt;<br>&lt;input type="submit" value="上传"&gt;<br>&lt;/form&gt;<br></pre>
<p>	姑且不说, 这个MAX_FILE_SIZE是多么的不可靠(所以基于浏览器的控制,都是不可靠的), 单纯从实现来讲, 我会慢慢介绍这个MAX_FILE_SIZE是如何起作用的.</p>
<p>	当用户选择了一个文件(laruence.txt), 并填写好文件描述(”laruence的个人介绍”), 点击上传后, 发生了什么呢?</p>
<h3>表单提交</h3>
<p>	在用户确定提交以后, 浏览器会发送如下类似格式的数据包到form中action属性指定的页面(在本例中是upload.php):</p>
<pre>//请求头<br>POST /upload.php HTTP/1.0\r\n<br>...<br>Host: www.laruence.com\r\n<br>...<br>Content-length: xxxxx\r\n<br>...<br>Content-type: multipart/form-data, boundary=--------------7d51863950254\r\n<br>...\r\n\r\n<br>//开始POST数据内容<br>---------------7d51863950254<br>content-disposition: form-data; name="description"<br>laruence的个人介绍<br>---------------7d51863950254<br>content-disposition: form-data; name="userfile"; filename="laruence.txt"<br>Content-Type: text/plain<br>... laruence.txt 的内容...<br>---------------7d51863950254<br></pre>
<p>	接下来, 就是服务器, 是如何处理这些数据了.</p>
<h3>接受上传</h3>
<p>
	当Web服务器, 此处假设为Apache(另外假设PHP是以module方式安装在Apache上的), 接受到用户的数据时, 首先它根据HTTP请求头, 通过确定MIME TYPE为PHP类型, 然后经过一些过程以后(这部分,可以参看我之前的<a target="_blank" href="http://www.laruence.com/2008/08/15/283.html">PHP Life Cycle ppt</a>), 最终会把控制权交给PHP模块.</p>
<p> 这个时候, PHP会调用sapi_activate来初始化一个请求, 在这个过程中, 首先判断请求类型, 此时是POST,
从而去调用sapi_read_post_data, 通过Content-type,
找到rfc1867的处理函数rfc1867_post_handler, 从而调用这个handler, 来分析POST来的数据.</p>
<p>	关于rfc1867_post_handler这部分的源代码, 可以在mian/rfc1867.c找到, 另外也可以参看我之前的<a target="_blank" href="http://www.laruence.com/2008/11/07/586.html">深入理解PHP之文件上传</a>, 其中也列出的源代码.</p>
<p>    然后, PHP通过boundary, 对于每一个分段, 都通过检查, 是否同时定义了:</p>
<pre>	name和filename属性(有名文件上传)<br>	没有定义name定义了filename(无名上传)<br>	定义了name没有定义filename(普通数据),<br></pre>
<p>	从而进行不同的处理.</p>
<pre>if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {<br>	char *pair=NULL;<br>	int end=0;<br><br>	while (isspace(*cd)) {<br>		++cd;<br>	}<br><br>	while (*cd &amp;&amp; (pair = php_ap_getword(&amp;cd, ';')))<br>	{<br>		char *key=NULL, *word = pair;<br><br>		while (isspace(*cd)) {<br>			++cd;<br>		}<br><br>		if (strchr(pair, '=')) {<br>			key = php_ap_getword(&amp;pair, '=');<br><br>			if (!strcasecmp(key, "name")) {<br>				//获取name字段<br>				if (param) {<br>					efree(param);<br>				}<br>				param = php_ap_getword_conf(&amp;pair TSRMLS_CC);<br>			} else if (!strcasecmp(key, "filename")) {<br>				//获取filename字段<br>				if (filename) {<br>					efree(filename);<br>				}<br>				filename = php_ap_getword_conf(&amp;pair TSRMLS_CC);<br>			}<br>		}<br>		if (key) {<br>			efree(key);<br>		}<br>		efree(word);<br>	}<br></pre>
<p>在这个过程中, PHP会去检查普通数据中,是否有MAX_FILE_SIZE.</p>
<pre> /* Normal form variable, safe to read all data into memory */<br>if (!filename &amp;&amp; param) {<br>	unsigned int value_len;<br>	char *value = multipart_buffer_read_body(mbuff, &amp;value_len TSRMLS_CC);<br>	unsigned int new_val_len; /* Dummy variable */<br>	......<br><br>	if (!strcasecmp(param, "MAX_FILE_SIZE")) {<br>                  max_file_size = atol(value);<br>    }<br><br>	efree(param);<br>	efree(value);<br>	continue;<br>}<br></pre>
<p>有的话, 就会按照它的值来检查文件大小是否超出.</p>
<pre>if (PG(upload_max_filesize) &gt; 0 &amp;&amp; total_bytes &gt; PG(upload_max_filesize)) {<br>	cancel_upload = UPLOAD_ERROR_A;<br>} else if (max_file_size &amp;&amp; (total_bytes &gt; max_file_size)) {<br>#if DEBUG_FILE_UPLOAD<br>	sapi_module.sapi_error(E_NOTICE,<br>		"MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved",<br>		 max_file_size, param, filename);<br>#endif<br>	cancel_upload = UPLOAD_ERROR_B;<br>}<br></pre>
<p>通过上面的代码,我们也可以看到, 判断分为俩部, 第一部分是检查PHP默认的上传上限. 第二部分才是检查用户自定义的MAX_FILE_SIZE, 所以表单中定义的MAX_FILE_SIZE并不能超过PHP中设置的最大上传文件大小.</p>
<p>通过对name和filename的判断, 如果是文件上传, 会根据php的设置, 在文件上传目录中创建一个随机名字的临时文件:</p>
<pre> if (!skip_upload) {<br>	/* Handle file */<br>	fd = php_open_temporary_fd_ex(PG(upload_tmp_dir),<br>			 "php", &amp;temp_filename, 1 TSRMLS_CC);<br>	if (fd==-1) {<br>		sapi_module.sapi_error(E_WARNING,<br>			 "File upload error - unable to create a temporary file");<br>		cancel_upload = UPLOAD_ERROR_E;<br>	}<br>}<br></pre>
<p>返回文件句柄, 和临时随机文件名.</p>
<p>之后, 还会有一些验证,比如文件名合法, name合法等.</p>
<p>如果这些验证都通过, 那么就把内容读入, 写入到这个临时文件中.</p>
<pre>.....<br>else if (blen &gt; 0) {<br>	wlen = write(fd, buff, blen); //写入临时文件.<br>	if (wlen == -1) {<br>	/* write failed */<br>#if DEBUG_FILE_UPLOAD<br>	sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));<br>#endif<br>	cancel_upload = UPLOAD_ERROR_F;<br>	}<br>}<br>....<br></pre>
<p>当循环读入完成后, 关闭临时文件句柄. 记录临时变量名: </p>
<pre>zend_hash_add(SG(rfc1867_uploaded_files), temp_filename,<br>	strlen(temp_filename) + 1, &amp;temp_filename, sizeof(char *), NULL);<br></pre>
<p>并且生成FILE变量, 这个时候, 如果是有名上传, 那么就会设置:</p>
<pre>$_FILES['userfile'] //name="userfile"<br></pre>
<p>如果是无名上传, 则会使用tmp_name来设置:</p>
<pre>$_FILES['tmp_name'] //无名上传<br></pre>
<p>最终交给用户编写的upload.php处理.</p>
<p>这时在upload.php中, 用户就可以通过move_uploaded_file来操作刚才生成的文件了~</p>
]]></content:encoded>
				</item>			
							<item>
					<title>在 PHP 中创建更好的名称空间</title>
					<link>http://www.phpv.net/html/1697.html</link>
					<comments>http://www.phpv.net/html/1697.html#comment</comments>
					<pubDate>Mon, 20 Jul 2009 15:36:17 +0800</pubDate>
					<dc:creator>admin</dc:creator>
					<category><![CDATA[PHP5研究[新]]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1697.html</guid>
					<description><![CDATA[PHP V5.3 支持为 PHP 类、常量和函数提供名称空间。使用名称空间避免命名冲突，并为 PHP 代码提供上下文。这些技巧为构建名称空间提供一些指导原则，从而充分利用名称空间带来的好处。]]></description>
					<content:encoded><![CDATA[<blockquote>PHP V5.3 支持为 PHP 类、常量和函数提供名称空间。使用名称空间避免命名冲突，并为 PHP 代码提供上下文。这些技巧为构建名称空间提供一些指导原则，从而充分利用名称空间带来的好处。</blockquote><!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->

<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
			<p>在 PHP V5.3
中引入的名称空间是为 PHP
类、常量和函数提供上下文的一种方式，从而可以将使用相同名称的元素看作是惟一的。惟一的名称避免了命名冲突，当两个类或函数使用相同的名称时就会发生这
种情况。有时这些 PHP 类表示现实世界中的相同对象，但它们的行为是完全不同的。名称空间能够确保您拥有正确的 PHP
类、常量或函数，并且要使用您的 PHP 类的人能够确保他们使用了正确的类。</p>
			<p>代码中的名称空间就像现实世界中的上下文。考虑一个表示现实世界中的汽车对象的类。例如，通过 Internet 销售汽车的公司使用的 <code>Automobile</code> 类的行为可能与保险销售公司使用的 <code>Automobile</code> 类完全不同。</p>
			<p>作为应用程序开发人员，您可能使用其他人编写的组件。您不能保证其他人永远不使用您已经使用的类名，但这些类的行为却大相径庭。在出现名称空间之前，PHP 开发人员通常将上下文构建到类名中，例如 <code>My_Enterprise_Person</code> 或 <code>XML_Validator</code>。</p>
			<p>清单 1 显示了一个位于名称空间中的类。</p>
			<br><a name="list1"><b>清单 1. 在名称空间中声明类</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>namespace IBM;<br>class Foo {<br>...<br>}<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<p>下面给出了一个例子，展示了如何在名称空间中引用类。</p>
			<br><a name="list2"><b>清单 2. 在名称空间中引用类</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>$foo = new \IBM\Foo();<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<p>在向所有类添加名称空间之前定义一个名称空间策略是个不错的
主意。尽管在某种程度上也可以不断地构建名称空间，但最好为名称空间确定一个通用结构，以方便名称空间的组织，并减少以后可能需要的修改。只要正确使用，
除了提供上下文之外，名称空间还可以用来组织 PHP 代码。</p>
			<p>其他语言（比如 Java™ 和
C#）在很久以前就使用名称空间。在选择名称空间命名方式上，我使用的约定类似于这些语言的约定，因为许多开发人员都对此比较熟悉，便于他们理解。不过，
与 Java 语言不同的是，PHP
中的名称空间与类所在的目录之间没有联系。您可以给类、函数或常量选择任意的名称空间。您甚至可以对一个文件使用多个名称空间。同时，PHP
名称空间也不同于 C#，您可以对类以外的函数或常量使用名称空间。</p>
			<p><a name="high_level"><span class="atitle">顶级名称空间</span></a></p>
			<p>如果您为某个组织构建名称空间，您可以使用组织名作为顶级域。一般情况下，使用组织名称创建顶级名称空间已经足以为 PHP 代码提供上下文，以及避免命名冲突，除非该组织编写大量用途不一的应用程序。</p>
			<p>清单 3 的示例显示了如何声明顶级名称空间。</p>
			<br><a name="list3"><b>清单 3. 顶级名称空间</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>namespace IBM;<br>...<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.phpv.net/uploadfile/month_200907/local_5E5YvyrPyi.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" border="0" height="6" width="8"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" alt="" height="4" width="100%"><br><br></td></tr></tbody></table><br><br><p><a name="subnamespaces"><span class="atitle">次级名称空间</span></a></p>
			<p><i>次级名称空间</i> 是顶级名称空间内部的名称空间。当顶级名称空间还不足以为 PHP 类建立上下文时，它们提供进一步说明。</p>
			<p>在创建次级名称空间时，不要凭一时的兴趣而过多地创建，这很重要。随着次级名称空间的增多，组织和引用它们就会变得越来越困难。如果您希望名称空间发挥双重作用，即避免命名冲突和组织 PHP 代码，那么就要更加注意这点了。</p>
			<p>在决定为了方便组织代码应该向另一个名称空间引入多少个次级名称空间时，我尝试将该数量限制为 7 个（上下浮动不超过 2），以利用数字 7 更加容易记住这个优势。这并不总是奏效的，但我将它作为一个指导原则，以确保不将名称空间划分为过多的次级名称空间。</p>
			<p>清单 4 的示例显示了在顶级名称空间中声明次级名称空间。</p>
			<br><a name="list4"><b>清单 4. 次级名称空间</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>namespace IBM\DeveloperWorks;<br>...<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<p>反斜杠（<code>\</code>）将次级名称空间 “developerWorks” 与顶级名称空间 “IBM” 分开。</p>
			<p>在声明次级名称空间时，您可以使用两个常见技巧，或同时使用它们。获取名称空间的常见地方是项目名或应用程序名；另一个地方是域名。</p>
			<p><a name="by_project"><span class="smalltitle">通过项目定义</span></a></p>
			<p>如果您使用组织名作为顶级名称空间，并且想通过次级名称空间来进一步提供上下文，那么可以使用项目名或应用程序名作为次级名称空间。例如，如果您构建一个称为 <i>Greeter</i> 的新应用程序（用于获取用户的名称并问候他们），那么清单 5 中的名称空间将为称为 <code>Prompt</code> 的类提供完整的上下文。</p>
			<br><a name="list5"><b>清单 5. 使用应用程序名作为次级名称空间</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>namespace IBM\Greeter;<br>class Prompt {<br>...<br>}<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<p>由于 <code>Prompt</code> 可能是多个应用程序或库的类名，所以为该名称空间添加组织名和项目名能够让这个 <code>Prompt</code> 类与其他同名的类区分开来。</p>
			<p><a name="by_domain"><span class="smalltitle">通过域定义</span></a></p>
			<p>使用域名是另一种选择次级名称空间的常见方式，如 <a href="http://www.ibm.com/developerworks/cn/opensource/os-php-namespaces/?ca=drs-tp4608#list6">清单 6</a> 所示。它也可以用于项目名之后，是否使用取决于您对可重用性的计划（见 “<a href="http://www.ibm.com/developerworks/cn/opensource/os-php-namespaces/?ca=drs-tp4608#reusability">根据可重用性命名</a>”）。</p>
			<p><i>域</i> 是对更大的问题域的一组分类。域的一个例子是在更大型的应用程序中处理帐户、客户和产品的 “Account”、“Customers” 或 “Products”。</p>
			<br><a name="list6"><b>清单 6. 使用域作为次级名称空间</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>namespace IBM\MyApp\Account;<br>class Address {<br>...<br>}<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.phpv.net/uploadfile/month_200907/local_5E5YvyrPyi.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" border="0" height="6" width="8"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" alt="" height="4" width="100%"><br><br></td></tr></tbody></table><br><br><p><a name="reusability"><span class="atitle">根据可重用性命名</span></a></p>
			<p>除了应用支持可重用性的模块概念之外，类和名称空间的命名方式也能够实现可重用性。有时不良的命名方式会损害可重用性，因为不佳的名称暗示着类仅能用于特定目的。同样，错误地应用名称空间可能会不必要地局限类的使用范围，让它们的重用变得困难。</p>
			<p>在
使用组织名的顶级名称空间中，应该保留 “Common”、“Core”、“Lib”
等可跨应用程序重用的名称空间。一个常见的例子是验证，其中针对整个企业的库存单位（SKU）、帐号或发票号的规则是一样的，从而获得合适的规则和长度。
对于 Validator 类，类似清单 7 的名称空间是不错的选择。</p>
			<br><a name="list7"><b>清单 7. 使用通用的 validation 名称空间</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>namespace MyCompany\Common\Validation;<br>class NotNullValidator {<br>...<br>}<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<p>在这里，组织名用作顶级域（“MyCompany”）。“Common” 名称空间用作项目。即使在编写这个类的同时也许正在编写一个特定的应用程序，该类一样可以在组织的任何项目中使用。最后，“Validation” 用作类的域。</p>
			<br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.phpv.net/uploadfile/month_200907/local_5E5YvyrPyi.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" border="0" height="6" width="8"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" alt="" height="4" width="100%"><br><br></td></tr></tbody></table><br><br><p><a name="aliases"><span class="atitle">使用别名</span></a></p>
			<p>尽管名称空间能够帮助您组织类并避免命名约定，但其缺点是名称过长。幸运的是，PHP 支持使用别名，因此可以在代码中使用更短的别名。清单 8 提供了一个示例。</p>
			<br><a name="listi8"><b>清单 8. 使用别名</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>use MyCompany\Common\Validation as Validators;<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.phpv.net/uploadfile/month_200907/local_5E5YvyrPyi.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" border="0" height="6" width="8"></td></tr></tbody></table><table class="no-print" align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" alt="" height="4" width="100%"><br><br></td></tr></tbody></table><br><br><p><a name="conventions"><span class="atitle">命名约定</span></a></p>
			<p>名称空间命名使用单词首字母大写或 PASCAL 命名约定，这与其他 PHP 约定一样，比如 PHP Extension 和 Application Repository (PEAR) 包命名和文件名。例如，清单 9 中的名称空间比 <a href="http://www.ibm.com/developerworks/cn/opensource/os-php-namespaces/?ca=drs-tp4608#list10">清单 10</a> 中的名称空间要好。</p>
			<br><a name="list9"><b>清单 9. 单词首字母大写或 PASCAL 命名</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>namespace MyNamespace;<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<p>避免使用与其他 PHP 约定冲突的命名和大小写约定。</p>
			<br><a name="list10"><b>清单 10. 使用糟糕的大小写约定</b></a><br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td class="code-outline"><pre class="displaycode">				<br>&lt;?php<br>namespace mynamespace;<br>...<br>?&gt;<br></pre></td></tr></tbody></table><br>
			<br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.phpv.net/uploadfile/month_200907/local_5E5YvyrPyi.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.phpv.net/uploadfile/month_200907/local_HxdPMTrIp1.gif" border="0" height="6" width="8"></td></tr></tbody></table><br><br><p><a name="N10167"><span class="atitle">结束语</span></a></p>
			<p>PHP 中的名称空间能够用于组织代码、避免命名冲突以及为类、函数和常量提供上下文。在名称空间中使用模式或约定让代码更易于理解，并且更易于引用和使用。</p>
]]></content:encoded>
				</item>			
							<item>
					<title>PHP招聘：如何面试应届生求职者</title>
					<link>http://www.phpv.net/html/1696.html</link>
					<comments>http://www.phpv.net/html/1696.html#comment</comments>
					<pubDate>Wed, 15 Jul 2009 16:58:33 +0800</pubDate>
					<dc:creator>抽烟的蚊子</dc:creator>
					<category><![CDATA[其它杂谈]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1696.html</guid>
					<description><![CDATA[为什么要招应届生？不是因为便宜，也不关职工忠诚度。我的原因是……应届生好调教。面试题共7道，1-3 是基础题，4-6 是数据库操作，7 算是综合能力...]]></description>
					<content:encoded><![CDATA[<p>为什么要招应届生？不是因为便宜，有人说还没跳过槽的人忠诚度能搞些，这也不尽然，有些人没经受过工作的压力，总以为自己碰巧找到个压力大的工作，
换换会好些。我的原因是……应届生好调教。在他们没有被各种枯燥乏味的工作折磨的以为写程序本来就这么 SB 之前好好洗洗脑子。</p><hr align="left"><p>1、2、3 是基础题，4、5、6 问的是数据库操作，7 算是综合能力吧。</p><p>1. 进制运算</p><p>可以是让他模拟一些简单的字符串函数，类似 bin2hex、base_convert、base64_encode，或者单纯的，让他手动算一下 7 进制的 54321 显示为 9 进制是多少。</p><p>应该高中或者之前就能接触到 2 进制 10 进制之间的换算了吧，当然，他当时很可能没听懂。通常的情况，如果以前没留意这个问题但有理解能力的，可能能在几分钟的做出一些成功不成功的尝试。至少不应该很茫然。最糟糕的情况，连整数的最大值是多少都不知道，那就算了。</p><p>2. 描述一下常见的关于读取文件内容的操作，及各自的特点</p><p>应
该不用迟疑太久就把 file、fopen、file_get_contents、readfile 列出来。表现好点还可以提下 readfile
的流式读取不占内存之类的。如果看的教材太老，可能只会说
fopen。最糟糕的辩解是不说跟数据库打交道比较多，文件操作没怎么接触过，完全无视文件静态化的存在。</p><p>3. 怎么模拟一个 POST 表单提交</p><p>答 socket 或者 cURL 都可以。</p><p>4. 列举一些常规优化方式</p><p>正
确索引（就不强求完全理解多列索引了，最好能知道每个查询只能用到一个索引），知道索引提高查询速度、降低插入速度。正确的字段类型（能知道 char
和 varchar 的区别和优缺点）。text
类字段可以单放一个表用主键关联。总之他能说的越多越好。顺便问问他他所知道的最大处理能力是每秒多少条，哪怕是测试环境里的
benchmarking（今天看到份简历，号称三年工作经验，将半个月三万条插入形容为他所遇到的最高的负载，写在简历的醒目位置）。</p><p>5. “你知道，把时间存在数据库里有两种方法，一种是用时间戳，就是 PHP 函数 time() 产生的那种整数，另一种是 MySQL 里字段类型设成 datetime。那么，为什么一定要后一种方式？”</p><p>最简单的一个例子，如果存的是时间戳，你无法按类似“所有周三的数据”这种方式显示内容。这表明了他的学习阶段：是否接触了类似日志分析类的东西。因为这些是早晚都要接触到的。</p><p>6. 简单联表查询</p><p>有这么两个表</p><p>user 表：</p><p><span style="font-family: 'Courier New';">id &nbsp;name<br>1 &nbsp; 张三<br>2 &nbsp; 李四<br>3 &nbsp; 王五<br>4 &nbsp; 赵六</span></p><p>apple 表：</p><p><span style="font-family: 'Courier New';">id &nbsp;user &nbsp;number<br>1 &nbsp; 1 &nbsp; &nbsp; 5<br>2 &nbsp; 3 &nbsp; &nbsp; 3<br>3 &nbsp; 1 &nbsp; &nbsp; 8<br>4 &nbsp; 4 &nbsp; &nbsp; 6<br>5 &nbsp; 3 &nbsp; &nbsp; 2<br>6 &nbsp; 4 &nbsp; &nbsp; 2</span></p><p>apple 表的 user 字段跟 user 表的 id 对应，一条 SQL 语句查出每个人都有多少苹果</p><p>如果他不知道 join，可能会这么写</p><p>SELECT user.name, SUM(apple.number) FROM user, apple WHERE user.id = apple.user GROUP BY user.id</p><p>正确答案应该是这样</p><p>SELECT user.name, SUM(apple.number) FROM user LEFT JOIN apple ON user.id = apple.user GROUP BY id</p><p>这两条语句的差别是，不用 join 无法显示出李四有 0 个苹果 <span style="white-space: nowrap;">-_-</span></p><p>7. 假设我们要做一个公交系统的常见服务，就是做查公交车怎么倒车的。假设完全由你自己来搞，我只关心最后结果，你会怎么做这个项目。说的越详细越好。</p><p>可能需要不断提示。考查一个人的做事能力，比方说他首先会想到需要数据，数据库应该怎么设计，有几个表，什么样的字段。<br>可
以加分的地方可以有这么几个点。给站名编
id，匹配数字的速度要远大于匹配字符串。站点之间要距离的数据，这样计算最优倒车路线应该能考虑到站数，倒车次数、距离等权值。如果很有远见，任意两点
之间的数据应该是提前算好的，比方说有 200 条公交线路和 2000 个站点，始发终点的组合可能是 2000 * 1000，每种线路可能有 1
- 6
种方案，有个表是来装这近一千万行结果的，如果有线路变化，再用本地的机器重新算一遍线路。这样整个系统才有实用价值。不然可能每次查询都需要耗费数秒或
者更长时间，只能当单机软件用。</p><hr align="left"><p>这些题本身是交流的话题，而不是“做对 5
道以上我就招你”这种门槛。我面试时每道题都会给予充分的时间，如果他做不上来，也起码能判断他的思考方式，而忌讳说“如果你不知道就明说，咱们赶紧做下
一题”。同时也能观察出性格等方面。比方说第 6 题，有人把 SUM 写成
COUNT，我就问他你看看前面写的是否有问题，同时又怕太明显，又补充一句“也可能什么错误也没有、我在误导你，你自己判断”，于是他就不再理会、继续
接着写完整个 SQL。再综合他的其他一些表现，我的结论是此人主见极强的，我不会用。属于出了 BUG 第一念头是 BUG
在解释器上、做出来的程序跟产品需求不符时会说是你产品没说明白的那种。相反，我很欣赏那些在做完第一道题的 7
进制转换后还知道验算的，因为既然是笔算就很容易出错。我觉得这种人思考严谨、负责任。</p><p>其他的一些知识，比方说 memcache、SVN、单元测试这些，都属于经验问题，应届生很少需要接触到这些东西（甚至文件静态化也很少碰到），不像上面，我需要以此来判断面试者对编程是否已经入门。</p><p>还是在 ngacn 上看到的一句话，团队需要两种人，要么 NB 的，要么听话的。</p>
]]></content:encoded>
				</item>			
							<item>
					<title>为什么设计师应该学习编写代码</title>
					<link>http://www.phpv.net/html/1694.html</link>
					<comments>http://www.phpv.net/html/1694.html#comment</comments>
					<pubDate>Wed, 08 Jul 2009 17:30:52 +0800</pubDate>
					<dc:creator>admin</dc:creator>
					<category><![CDATA[前端交互]]></category>
					<guid isPermaLink="false">http://www.phpv.net/html/1694.html</guid>
					<description><![CDATA[通常，在完成了一件网页设计后，设计师的无知都会显露无遗而备受指责。他们把创建网页代码的繁重工作都留给了程序员们。这种现象不只出现在网络开发行业，在软件及游戏开发业也是如此。]]></description>
					<content:encoded><![CDATA[<p>通常，在完成了一件网页设计后，设计师的无知都会显露无遗而备受指责。他们把创建网页代码的繁重工作都留给了程序员们。这种现象不只出现在网络开发行业，在软件及游戏开发业也是如此。</p>
<p><img src="http://www.phpv.net/uploadfile/month_200907/local_aWMxajPddV.jpg" alt=""></p>
<p>残酷的事实就是：<strong>开发进度可能会因设计师而停滞不前。</strong>为了追求最佳效率，设计师不仅需要描描画画，还需要能把它做出来！本文中，我想与读者分享一些为什么设计师需要学习编写代码的理由。</p>
<h4>做现实可行的设计</h4>
<p>有了一个最终产品将如何实现的明确印象，设计师将拿出更多实际可行的概念。作为开发进程中不可或缺的一份子，设计师肩负着确保他们的设计能够顺利转
移到网络介质上，同时还要考虑其可用性，网页易读性和可实现性。一个对用户友好的网站不仅有简洁清晰的浏览顺序逻辑，还向用户提供一切所需的信息而不会显
得咄咄逼人或是杂乱无章。想要知道一种 Web 布局是否可行的唯一途径就是亲自去了解如何建立一个网页。</p>
<h4>使沟通更轻松</h4>
<p>在几乎所有的设计与实现各自独立的产品中，设计组和实现组从没有满足过对方的期望，尤其是那些无形的产品，比如网站，软件和游戏。这通常归结于<strong>产品的期望和产品可行性的相互妥协</strong>，目前看来，这是难以完美统一的。解决之道是：设计师应该亲身尝试设计作品的实现，以避免沟通中的混淆，误解和误传。</p>
<h4>方便的迭代开发过程</h4>
<p>一个实践中的设计不应是绝对的。我的意思是，设计应该是灵活友好的，能够在修改以迎合系统技术限制的同时不扭曲其原有内涵。这些重复但必要的改动只
能由原设计师来实现。一个设计师/开发者能够比开发人员把设计重提到设计师手里进行改动更加高效。而且设计师和开发者之间——事实上经常如此——会产生摩
擦。</p>
<h4>更好更和谐的结果</h4>
<p>我常常喜欢把软件，网络或是游戏开发想成是管弦乐，而设计师是作曲家，开发者是乐团的指挥家。想象一下二者是同一个人将会怎样？交响曲将会是令人惊叹的，迷人的，纯正的！不仅是大师的神作，而且还是其本人亲自指挥的！</p>
<h4>缩短开发时间</h4>
<p>设计师同时充当程序员的角色意味着设计和编码的进度即使不是同时的也是连续的。结果就是开发周期的缩短——谁会不关心效率呢？</p>
<h4>设计师更加市场化</h4>
<p>现代的设计师需要提升自身的能力以保持个人价值，有一套技能是远远不够的，我们往往需要戴着不同的头衔：设计师，前端开发者，文章作者和项目经理。</p>
<p>通过学习实现你自己的设计，而不是让设计成为开发者手中的孤儿——你提升了自身价值。毕竟，在简历中提到设计和编码技能不会有坏处。相反，在这个金融危机时代的企业重组（参见：大规模裁员）和缩减开支的环境下，还能够强调一个人的重要性而免遭解雇。</p>
<p>然而，即使有这么多的理由支持设计师学习编写代码，这里还是有反对的声音。</p>
<p>引用 Lukas Mathis 的一篇有争议性的文章“设计师不是程序员”（<strong>注1）</strong></p>
<blockquote><p>如果设计师实现自己的设计，他会受制于两个不同的目标：代码的整洁和良好的用户体验。这两个目标是相互矛盾的。如果你要实现你自己的设计，你必然会为了代码的质量而妥协，这是不利于交互设计的。</p>
<p>实现自己设计的设计师面临着两个问题：他们知道一个很棒的新思路会建立混乱的代码，他们也知道如果改进用户体验，现有的代码会被打乱。这两者相互矛盾，因为用户体验都在于小的细节，而这些小细节最终毁于他们的不忍心使代码变得混乱。</p></blockquote>
<p>这恰如其分的总结了“Web 开发纯化者”们所采取的强硬立场。他们是守旧派，倡导在设计和开发之间划清界限。显然，<strong>设计师为人类创作，开发者为机器创作。</strong>因此，用户体验设计师们应该设计出最可行的用户界面并让开发者做出最可行的编程决策。虽然这有一定的道理，但当我研究一个用户界面的时候，我从代码中寻找灵感的努力却以失败而告终。总之，在头脑中有一个技术及可用性限制的正确观念还是更有好处。</p>
<h4>写在最后</h4>
<p>归根结底，所开发项目的规模可能最终决定着设计师和开发者的角色。一个小型的应用可以由一个项目经理（<strong>注2）</strong>一手掌控，而一个大型的系统必然需要不同的专业人才！</p>
<p><strong>注1</strong> Mathis-Lukas——“<a target="_blank" href="http://ignorethecode.net/blog/2009/03/10/designers-are-not-programmers/">Designers are not Programmers</a>”——ignore the code</p>
<p><strong>注2</strong> Spolsky-Joel——描述了一个叫做“设计师兼程序员”的职位——“<a target="_blank" href="http://www.joelonsoftware.com/items/2009/03/09.html">How to be a program manager</a>”——Joel on Software</p>
<p>作者 John Urban 是加州大学的大二学生，主修计算机科学。</p>
<p>英文原文 <a target="_blank" title="http://sixrevisions.com/web_design/why-designers-should-learn-how-to-code/" href="http://sixrevisions.com/web_design/why-designers-should-learn-how-to-code/">http://sixrevisions.com/web_design/why-designers-should-learn-how-to-code/</a></p><p><br></p>转自：http://ineu.org.cn/blog/index.php/archives/431
]]></content:encoded>
				</item>			
					
	</channel>
</rss>
