<?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/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>玄猫的窝-韩国峰的博客 &#187; PHP</title>
	<atom:link href="http://www.hanguofeng.cn/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.hanguofeng.cn</link>
	<description>韩国峰的博客,关注Web技术与电子商务。</description>
	<lastBuildDate>Sat, 04 Sep 2010 14:39:38 +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项目开发(3)–切分你的系统</title>
		<link>http://www.hanguofeng.cn/archives/web-server/php-project-development-3?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=php-project-development-3</link>
		<comments>http://www.hanguofeng.cn/archives/web-server/php-project-development-3#comments</comments>
		<pubDate>Mon, 12 Jul 2010 12:04:09 +0000</pubDate>
		<dc:creator>hanguofeng</dc:creator>
				<category><![CDATA[Web服务器端技术]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[听小韩聊PHP项目开发]]></category>

		<guid isPermaLink="false">http://www.hanguofeng.cn/?p=144</guid>
		<description><![CDATA[【写在前面的话：看看本文的时间，最后一次保存是去年的八月份，想想，还是先发表一下，然后待续，老规矩，在本文完成之前请不要转载。】 你是一个有控制欲的人么？你希望把控你的项目么？那么，切分他们吧。 1、为什么要切分你的项目 我们是邪恶的 -.-。我们希望把控我们的项目，所以，我们需要切分它。 想像一下，你有一个生日蛋糕，你想吃掉它，那么，按照惯例，作为寿星的你，应该先切分它，什么？你还要点蜡烛？OMG，你要在吹蜡烛时喷口水在蛋糕上吗？你的口味好重。 切分代码，大体上来说，在控制进度、应对变化、简化逻辑、代码复用、分工协作等方面，都有相当的好处。 1.1、控制进度 首先来说控制进度，当你开始开发一个大型站点时（当然，更多的时候是“你们”），作为项目经理的你来讲，你需要时不时的应对来自你的上级或者你的客户的询问&#8211;“小韩，做了多少了，还有多久能做完啊”。这个时候，你总不能说，“哦，我做了一些了，还有一段时间能做完。” 你的领导希望听到的是，系统一共有x个模块，我做完了x个，剩下x个模块，难度有些大，可能还需要x天的时间，等所有模块都完成了，再整体整合测试一下，就OK了。这样回答，我想你的表现会让你的领导觉得，你是一个思路清晰，能够把控的项目管理人员。这里再容我跑题一下，一般认为，管理职能分为“计划、组织、协调、控制”等。其中“计划”则首先依赖于对项目的切分，如果不能切分项目，则无从进行计划。 1.2、应对变化 我们都知道，项目，尤其是软件项目是多变的，这种变化可能来自于前期沟通的不完善，也可能来自于随着时间的发展，客户或软件使用者的需求随之发展而发生变化。如果项目中所有的部分都是互相缠绕的，那么则牵一发而动全身，你甚至无法对一个简单的变量名进行改变，而使得系统的其他部分不受到干扰。然而此时，如果对系统进行划分，将其分为若干层次、若干模块，层次与层次、模块与模块之间通过既定协议（如接口）进行通讯，则可以将原有的整体复杂系统切分为若干个子系统、子模块、子程序，各程序只要保持其输入、输出不变，则其内部的代码可以方便的更改而不怕会影响到外部。 我举个例子来讲，你可能用以下代码处理用户的登录以及其登录会话的持久化（Session）。 //登录代码 if&#40;$success_login&#41; //假设$success_login为上一步判断用户名密码正确与否的标记 &#123; $_SESSION&#91;'user_name'&#93; = $user_name; $_SESSION&#91;'password'&#93; = $password; &#125; 而使用如下代码判断是否登录 if&#40;isset&#40;$_SESSION&#91;'user_name'&#93;&#41;&#41; &#123; //do something &#125; 那么假设有一天，你想使用username作为保存用户名的Session变量名称，则你需要找出所有形如$_SESSION['user_name']的代码，并修改，一旦有遗漏，你的程序将会出现难以查找的bug。 这就是因为在代码中，把用户登录会话的部分耦合在了全部的系统当中。实际上，你应该专门有一个管理用户登录会话的模块，比如叫做SessionManager，你的代码则可能变为这样： /** * 设定登录会话 */ if&#40;$success_login&#41; //假设$success_login为上一步判断用户名密码正确与否的标记 &#123; SessionManager::SetLoginUser&#40;$user&#41;; &#125; &#160; /** * 判断登录状态 */ if&#40;SessionManager::IsLogined&#40;&#41;&#41; &#123; //do something &#125; 这样，你在系统中，无需过度关注用户会话保存的具体实现，只要去调用SessionManager这个管理器的相关方法就可以了，而一旦发生前面提到的变化，你可以在SessionManager的内部完成此修改，而不会将这个问题渲染到全部代码。 1.3、简化逻辑 也许大部分普通的Web站点并没有复杂的逻辑，但是，随着网络世界越来越精彩，Web站点也会逐渐面临处理复杂逻辑的任务。一旦你面临复杂的系统，其中可能难倒你的，大部分不会是技术问题，而是逻辑问题，我们应当承认我们人类中的大部分，思维的稳定性和思维长度，都是有限的，我举个例子来说，在下棋的时候，在头脑中演算下一步应该如何走，对手针对你的下一步如何走这样的逻辑，没有经过一定锻炼的人，是不可能演算很多步的。对于系统逻辑来说也是一样的，同时考虑过多的问题，以及这些问题之间的关系，会让你无法承受，然而此时将一个大的、复杂的问题切分为若干小问题，在同一时刻只关注一个小问题，则可以让自己轻松快乐的去进行程序的编写。再举个例子，比如我们要写一个MSN的客户端，那么实际上是有很多问题要考虑的，你的程序如何与服务器通讯，如何构造和发送数据，如何接受和处理数据，如何将数据显示在界面上……so many，这个时候你可以将你的系统切分为若干的模块，有的模块去处理网络通讯，有的去处理数据包的解析和构造，有的去处理界面显示，有的去处理各种事件的调度，等等等等，在各个模块中，你还可以进一步划分，直到单个类遵循单一职责原则，而一个模块间各个类都是聚合的……等等等等，这里有很多方法和技巧，我们稍后会详细讨论。 [...]]]></description>
			<content:encoded><![CDATA[<p>【写在前面的话：看看本文的时间，最后一次保存是去年的八月份，想想，还是先发表一下，然后待续，老规矩，在本文完成之前请不要转载。】</p>
<p>你是一个有控制欲的人么？你希望把控你的项目么？那么，切分他们吧。</p>
<h2>1、为什么要切分你的项目</h2>
<p>我们是邪恶的 -.-。我们希望把控我们的项目，所以，我们需要切分它。</p>
<p>想像一下，你有一个生日蛋糕，你想吃掉它，那么，按照惯例，作为寿星的你，应该先切分它，什么？你还要点蜡烛？OMG，你要在吹蜡烛时喷口水在蛋糕上吗？你的口味好重。</p>
<p>切分代码，大体上来说，在控制进度、应对变化、简化逻辑、代码复用、分工协作等方面，都有相当的好处。</p>
<h3>1.1、控制进度</h3>
<p>首先来说控制进度，当你开始开发一个大型站点时（当然，更多的时候是“你们”），作为项目经理的你来讲，你需要时不时的应对来自你的上级或者你的客户的询问&#8211;“小韩，做了多少了，还有多久能做完啊”。这个时候，你总不能说，“哦，我做了一些了，还有一段时间能做完。”</p>
<p>你的领导希望听到的是，系统一共有x个模块，我做完了x个，剩下x个模块，难度有些大，可能还需要x天的时间，等所有模块都完成了，再整体整合测试一下，就OK了。这样回答，我想你的表现会让你的领导觉得，你是一个思路清晰，能够把控的项目管理人员。这里再容我跑题一下，一般认为，管理职能分为“计划、组织、协调、控制”等。其中“计划”则首先依赖于对项目的切分，如果不能切分项目，则无从进行计划。</p>
<h3>1.2、应对变化</h3>
<p>我们都知道，项目，尤其是软件项目是多变的，这种变化可能来自于前期沟通的不完善，也可能来自于随着时间的发展，客户或软件使用者的需求随之发展而发生变化。如果项目中所有的部分都是互相缠绕的，那么则牵一发而动全身，你甚至无法对一个简单的变量名进行改变，而使得系统的其他部分不受到干扰。然而此时，如果对系统进行划分，将其分为若干层次、若干模块，层次与层次、模块与模块之间通过既定协议（如接口）进行通讯，则可以将原有的整体复杂系统切分为若干个子系统、子模块、子程序，各程序只要保持其输入、输出不变，则其内部的代码可以方便的更改而不怕会影响到外部。</p>
<p>我举个例子来讲，你可能用以下代码处理用户的登录以及其登录会话的持久化（Session）。</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//登录代码</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$success_login</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//假设$success_login为上一步判断用户名密码正确与否的标记</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$_SESSION</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'user_name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$user_name</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$_SESSION</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$password</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>而使用如下代码判断是否登录</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SESSION</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'user_name'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #666666; font-style: italic;">//do something</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>那么假设有一天，你想使用username作为保存用户名的Session变量名称，则你需要找出所有形如$_SESSION['user_name']的代码，并修改，一旦有遗漏，你的程序将会出现难以查找的bug。</p>
<p>这就是因为在代码中，把用户登录会话的部分耦合在了全部的系统当中。实际上，你应该专门有一个管理用户登录会话的模块，比如叫做SessionManager，你的代码则可能变为这样：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/**
* 设定登录会话
*/</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$success_login</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//假设$success_login为上一步判断用户名密码正确与否的标记</span>
<span style="color: #009900;">&#123;</span>
 SessionManager<span style="color: #339933;">::</span><span style="color: #004000;">SetLoginUser</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
* 判断登录状态
*/</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>SessionManager<span style="color: #339933;">::</span><span style="color: #004000;">IsLogined</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #666666; font-style: italic;">//do something</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>这样，你在系统中，无需过度关注用户会话保存的具体实现，只要去调用SessionManager这个管理器的相关方法就可以了，而一旦发生前面提到的变化，你可以在SessionManager的内部完成此修改，而不会将这个问题渲染到全部代码。</p>
<h3>1.3、简化逻辑</h3>
<p>也许大部分普通的Web站点并没有复杂的逻辑，但是，随着网络世界越来越精彩，Web站点也会逐渐面临处理复杂逻辑的任务。一旦你面临复杂的系统，其中可能难倒你的，大部分不会是技术问题，而是逻辑问题，我们应当承认我们人类中的大部分，思维的稳定性和思维长度，都是有限的，我举个例子来说，在下棋的时候，在头脑中演算下一步应该如何走，对手针对你的下一步如何走这样的逻辑，没有经过一定锻炼的人，是不可能演算很多步的。对于系统逻辑来说也是一样的，同时考虑过多的问题，以及这些问题之间的关系，会让你无法承受，然而此时将一个大的、复杂的问题切分为若干小问题，在同一时刻只关注一个小问题，则可以让自己轻松快乐的去进行程序的编写。再举个例子，比如我们要写一个MSN的客户端，那么实际上是有很多问题要考虑的，你的程序如何与服务器通讯，如何构造和发送数据，如何接受和处理数据，如何将数据显示在界面上……so many，这个时候你可以将你的系统切分为若干的模块，有的模块去处理网络通讯，有的去处理数据包的解析和构造，有的去处理界面显示，有的去处理各种事件的调度，等等等等，在各个模块中，你还可以进一步划分，直到单个类遵循单一职责原则，而一个模块间各个类都是聚合的……等等等等，这里有很多方法和技巧，我们稍后会详细讨论。</p>
<h3>1.4、代码复用</h3>
<p>代码复用的一个重要基础是分割变化与不变的部分，并分别进行编程。还以我们上面的MSN客户端的例子来说，其处理网络通讯的模块，在其他的程序中是不是也可以使用呢？答案是肯定的，但是……这要求你能够良好设计这个模块，权衡其边界，以使其具有普适性。这种基础类的实现，不应当关联具体项目的问题，比如说最简单的，你的方法名，不应当叫做send_msn_request，而只是send_request，这只是一个很简单的例子，但是却说明了，你要考虑你系统中的某些聚合功能，是不是可以在其他项目中使用的，如果是，请将其切分出来，并撰写并非是与当前项目紧密耦合的代码，你可以使用一个适配器将其配接到当前项目中，而不是将其直接为当前项目撰写。</p>
<p>关于代码复用的内容，您还可以查看<a href="http://www.ibm.com/developerworks/cn/java/reuse/">http://www.ibm.com/developerworks/cn/java/reuse/</a>获得更多信息。</p>
<h3>1.5、分工协作</h3>
<p>分工协作首先要求在“工”上有的可分，现代生产是要求详细分工，流水线方式作业的，试想，哪怕一个简单的MP3，有做芯片的机器，有开发嵌入式系统的工程师，还有利用模具生产的合作工厂，最后将各个部分拼接起来，成为你手中那个会发声、可以控制的小玩意。程序开发也是一样的。每一个系统，无论简单复杂，总是由若干个子系统组成的，这些子系统通常是功能内聚的，并通过某些特定方式与其他子系统进行协作。简单说，你所看到的这个WordPress的系统，有文章的子模块、有分类/Tag的子模块，那么我们是否可以让两个人分别去开发文章的子模块和分类/Tag的子模块呢，答案是肯定的，合作者首先坐在一起，定义各自的系统边界，开发分类/Tag子模块的工程师无需了解文章是由标题、内容，甚至图片组成的，他只了解，需要给特定的文章（通过文章的id来作为关键标记），进行分类，或者标记Tag，同理，开发文章子模块的工程师也无需了解Tag和分类的区别，只需要做他的文章模块的CURD就可以了，彼此之间不需要了解太多，是增强系统稳定性，在变化时可以敏捷修改而不担心影响其他部分的重要方式。这可以降低系统的开发和修改成本，工程师之间不必担心进行了重复的工作，因为子系统边界已经确定，每个人需要做什么是非常清晰的，同时，他们不必担心他们所完成的功能如何被调用，因为这些调用规则在切分系统时就明确了。他们也不必考虑其他子系统是否会影响他的系统，包括其他子系统的bug或者修改，因为各子系统是<a href="http://www.blogjava.net/realsmy/archive/2007/04/08/109245.html" target="_blank">高内聚、低耦合</a>的，子系统的具体实现方式不会过多影响其他系统。</p>
<h2>2、如何切分你的系统</h2>
<p>切分系统是一种艺术而不是一种技术。从不同的角度看某个物体，你会得到不同的投影，一个正方形的投影，那么其原物体一定是正方体吗，当然未必。从不同的角度看待系统，就会有不同的切分方式。而我们要做的就是，试图从各个角度来看待系统，避免盲人摸象，最终选择一种权衡的、折衷的，对于系统的发展方向最契合的方式来切分。不同的程序员有不同的切分习惯，而我们也无法武断的去说一定要按照某种方式切分。毕竟，我们不是为了切分系统而切分，而是要达成某种目的，这些目的我在上面笼统的谈过，比如说，针对分工协作，如果团队中程序员的水平有一定差距，那么可以将相对内核的复杂部分切出来，交由有经验的程序员来完成，即时它可能在其他方面并不能达到你的目的。</p>
<p>切分系统有几种角度，让我们由浅入深的聊一聊。</p>
<h3>2.1、横向切分</h3>
<p>对于系统的切分，横向切分是最常见的，例如<a title="MVC" href="http://zh.wikipedia.org/wiki/MVC" target="_blank">MVC</a>模式：<strong>MVC</strong>（Model-View-Controller，模型—视图—控制器模式）用于表示一种软件架构模式。它把软件系统分为三个基本部分：模型（Model），视图（View）和控制器（Controller）。</p>
<p>这种切分方式主要考虑了系统是由几个层次来完成的，各个层次之间的功能是内聚的，比如在MVC中，Model层负责数据交互，它永远不必理解数据在界面上是如何展示的，同理，View层也不必理解数据是从MySQL数据库还是SQL Server甚至是文件中的哪个取出的。</p>
<p>这种层次的划分，可以将系统功能划分为几个大部分，这几个大部分相对独立，然而又通过行为/数据被粘合在一起，从而使得其中某个部分发生变化时，其他部分不至于那么敏感，比如，网站的界面是会频繁改版的，然而你会发现，几乎大部分情况都是，界面上的元素摆放发生了变化，但是数据本身并没有任何变化，那么我们只需要改变View层就可以了，你的C和M层的代码一点都不用改动。</p>
<p>另一个名词叫做“三层架构”，实际上和MVC类似，也有人将MVC直接成为三层架构。其代表是微软的示例程序PetShop（<a title="PetShop的系统架构设计分析" href="http://www.cnblogs.com/wayfarer/archive/2006/04/14/375382.html" target="_self">架构详细分析看这里</a>）。其将系统大致分为DAL（Data Access Level，数据访问层）、BLL（Bussines Logic Level，业务逻辑层）以及界面表示层。</p>
<p>但是，我窃以为，仅有MVC是不够的。在MVC中，Model层的功能实际上是可以再分为数据逻辑和业务逻辑两个层次，即更倾向于三层架构。业务逻辑层可以复用多个数据逻辑层，这在仅有Model层的系统中是难以做到的，同时，业务逻辑是可能发生频繁变更的，此时简单的数据逻辑并没有发生任何变化，不需要花代价和承担风险进行修改。我举个例子来说，我们要设计一个用户系统，该系统有注册、登录、修改信息等功能，此时，我们可以根据需求制定出一个业务逻辑层，你可以将其叫做LogicOperation/UserOperation层（下文简称UserOper），在该层中切合需求进行功能的设计，即Login、Regist、ModifyInfo，那么，我们是否在这个层次中就开始撰写关于数据库操作的代码呢，答案是否定的，因为你会发现，在Login功能中，你需要去查询用户名是否存在这样的信息，在Regist中，你同样会查询该信息，此时，你应该继续抽象出一个功能相对原子化的数据操作层，即DataManager/UserManager，在UserManager中，实现标准的CURD（Create、Update、Read、Delete）功能，以及某些可能用到的其他功能，但是这些方法应该是原子化的，可以由UserOper组合调用，例如在Regist中，可能通过UserManager的IsAccountExist方法查询用户名是否存在，然后用CreateUser方法建立用户，而在Login中，首先通过IsAccountExist方法查询用户名是否存在，然后用ReadUserByAccount方法来获得用户信息，并继而比对密码，等等，你会发现，LogicOperation层是对DataManager层方法的组合调用，而其组合方式就是具体的业务逻辑。</p>
<h3>2.2、纵向切分</h3>
<h3>2.3、混合切分</h3>
<h3>2.4、切分粒度</h3>
<h2>3、切分案例</h2>
<h2>3.1、一个CMS系统的切分</h2>
<h3>3.2、一个博客系统的切分</h3>
<h3>3.3、一个校内网APP程序的切分</h3>
<h2>4、切分作业</h2>
<h3  class="related_post_title">相关内容</h3><ul class="related_post"><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-2" title="听小韩聊PHP项目开发(2)&#8211;观察你的项目">听小韩聊PHP项目开发(2)&#8211;观察你的项目</a></li><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-1" title="听小韩聊PHP项目开发(1)&#8211;开题的话">听小韩聊PHP项目开发(1)&#8211;开题的话</a></li><li><a href="http://www.hanguofeng.cn/archives/security/configure-fast-in-lamp-on-windows-with-xampp" title="Windows下AMP平台配置FastCGI方法（以xampp为基础）">Windows下AMP平台配置FastCGI方法（以xampp为基础）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.hanguofeng.cn/archives/web-server/php-project-development-3/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[听小韩聊PHP项目开发]]></series:name>
	</item>
		<item>
		<title>听小韩聊PHP项目开发(2)&#8211;观察你的项目</title>
		<link>http://www.hanguofeng.cn/archives/web-server/php-project-development-2?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=php-project-development-2</link>
		<comments>http://www.hanguofeng.cn/archives/web-server/php-project-development-2#comments</comments>
		<pubDate>Sun, 28 Jun 2009 05:42:06 +0000</pubDate>
		<dc:creator>hanguofeng</dc:creator>
				<category><![CDATA[Web服务器端技术]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[听小韩聊PHP项目开发]]></category>

		<guid isPermaLink="false">http://www.hanguofeng.cn/?p=125</guid>
		<description><![CDATA[Hello，时隔半年，我终于继续了 =.= 1、为什么要观察你的项目&#8211;需求的重要性。 俗话说，磨刀不误砍柴工，当开始一个项目时，我希望你就像在街上看到了美女，你要先好好打量打量，然后再思考，“啊，我怎么去问她的电话呢~” So,same as our projects. 当开始一个项目时，你应当首先审视的是项目的需求，要注意了，除非是你自己为自己闲着没事做的东西，其他的项目，都是为别人做的，怎么理解呢，我的意思是说，你项目的目的就是满足别人的需求。软件实际上是一种商品。所谓商品，就是商品是为交换而生产（或用于交换）的对他人或社会有用的劳动产品[百度百科]。请注意“对他人或社会有用”，这就是在讲，我们所编写的软件是为了满足需求而存在的，如果不能满足需求，哪怕你用了再高的技术，软件做的再漂亮，运行效率再高，都不能被称之为一款合格的软件。 为什么突然要扯这么远呢，是因为，我曾经和很多人一样，在做开发的时候，开始的时候无时不刻的都在想，这个东西有什么技术创新点，什么地方的效率会很低，应该解决，后来我听到了一句话，叫做“过早优化是万恶之源（premature optimization is the root of all evil&#8211;Donald Knuth）”，可能的确有那样一些项目，他们要求很高的效率，或者，该项目的需求者一直在询问你关于效率的问题，但是无论如何，在你什么都没有的时候，你就什么都不能做，就像你并没有一个女儿，你却时刻想着如何去打扮她一样毫无意义。 请记住，我们所编写的软件，它的第一要务是满足需求，当然，运行效率、界面美化可能是需求的一部分（非功能性需求，我们稍后会谈到），但是请将其作为需求考虑，而不是贯穿软件的全部。 关于需求，这里有一幅漫画，来源未知（提示：你可以点击图片放大）： 另外还有此图片的中文版：http://picasaweb.google.com/lh/photo/ZK59I5p5-jfsc7kl213htQ?feat=directlink 2、我要观察到什么&#8211;什么是需求 “需求是产品必须完成的事以及必须具备的品质。需求存在的原因要么是该类型的产品要求一定的功能和品质，要么是客户希望需求成为交付的产品的一部分。” &#8211;《掌握需求过程》ISBN:9787115159830 从上面的漫画中，可以很有趣的发现，由于沟通方式，对目标的理解差异和技术水平的不同，都会让需求在传递中发生变化，这种变化有时可能是致命的，我们人类在沟通时多采用语言，然而语言，尤其是口头语言，极易发生变化。因此，就需要大家对需求有一个统一的认识，什么是需求，需求应该包括哪些内容，不应该包括哪些内容，应该如何去分析需求。 本节引言中的话，严格来讲不是对需求的定义，让我们来看IEEE软件工程标准词汇表(1997年)中“需求”的定义： (1)用户解决问题或达到目标所需的条件或权能(Capability)。 (2)系统或系统部件要满足合同、标准、规范或其它正式规定文档所需具有的条件或权能。 (3)一种反映上面(1)或(2)所描述的条件或权能的文档说明 软件需求包括三个不同的层次—业务需求、用户需求和功能需求—也包括非功能需求。业务需求( business requirement)反映了组织机构或客户对系统、产品高层次的目标要求，它们在项目视图与范围文档中予以说明。用户需求(user requirement) 文档描述了用户使用产品必须要完成的任务，这在使用实例(use case)文档或方案脚本(scenario)说明中予以说明。功能需求(functional requirement)定义了开发人员必须实现的软件功能，使得用户能完成他们的任务，从而满足了业务需求。所谓特性(feature)是指逻辑上相关 的功能需求的集合，给用户提供处理能力并满足业务需求。 简单来说，需求就是说明你软件将要满足的用户需要，需求是你软件的功能列表，这里的功能可能包括看得见的功能和看不见的功能。同时需要注意实际用户（用户是重要的需求分析参与者，难以想象一个只有开发者而没有用户参与的需求分析，所得出的是什么）可能对需求的理解有误，有时他们甚至不了解活无法向你描述出他的需求，也有时，他会“啰啰嗦嗦”的向你讲一堆不是需求的东西。 同时，需求还包括非功能的部分，例如，“单次搜索查询必须在0.1秒内完成”、“用户传输文件的速度不应低于其网络最高可用带宽的50%”，这些内容并非软件的功能性要求，但是实际上是软件的使用者使用软件体验、感受的重要感受点甚至是其是否能完成功能性需求的制约。 3、我没有马王爷的第三只眼&#8211;那么我如何分析需求呢 哦，这很麻烦，是的，好吧，我们退一步，作为开发人员，你可以让你的产品经理去和客户打交道，但是你必须和你的产品经理打交道，同时，你还必须和你的代码打交道。 与产品经理打交道和与代码打交道是两码事，八杆子打不到一块，你不能和产品经理讲if(xxx)  {} ，也不能去问你的代码，这里是让用户操作的，还是你丫自动操作的。 在与产品人员打交道时，你有责任用他们的语言来描述问题，这并不是单纯为了对方能够听懂你说什么，更重要的是，这会大大减少你们在交流沟通中的误解。所以，熟知你所在的行业，熟悉他们的业务，如果你要开发财务系统，请去阅读财会相关书籍，如果你要开发ERP系统，请去和工人师傅、基层管理人员多聊聊，在拓展你领域的同时，也会让你对你的编程思想有新的看法。 在与代码打交道的时候，你需要是一个好的建筑师，你应当构建严谨、运行健壮、可扩展性强的代码，这要求你在充分理解需求的情况下，看到需求的发展方向以及需求中可能发生变动的情况，甚至你需要和产品经理、客户去沟通，提出你的想法，当你问道“我觉得这里这样做的话，系统可能存在不稳定的因素，如果怎么怎么样做，不仅系统稳定了，您的操作也会更方便”，客户恍然大悟，你又减轻了工作量，何乐不为呢。 在理解需求、分析系统时，我建议你首先这样做： 将系统中存在的活动者都列出来，然后依次列出他们的操作功能和反应。 比如，一个简单的文章系统，我们可能这样去描述它 普通用户：注册、登录、找回密码、修改个人信息、查看类别、查看文章、查看某个类别下的文章、输入关键字搜索文章、发表评论、当别人发表对自己评论的回复时收到邮件。 管理员：查看用户信息、CURD（Create-Update-Read-Delete）类别、CURD文章 在上面的需求描述中，涉及了两个活动者，分别是“普通用户”和“管理员”，同时两个活动者都有若干功能，其中“普通用户”的“当别人发表对自己评论的回复时收到邮件”实际上不是用户的主动操作，而是用户对某个操作的反应，需要注意的是，这样的信息也需要在需求分析中体现。 需求分析可以体现为UML用例图，其好处是更直观，同时由于是统一化的表达，更有助于沟通，其他程序员可以更方便的理解你的意思，而不容易出现理解误差。 关于UML用例图方面的内容，可以到http://hi.baidu.com/jyangstu/blog/item/5d2f89131ef270c6c3fd7833.html查看一份简介。 我的需求方法实际上是用例图的一个超级简版，这个方法不能体现活动者与活动者、用例与用例（就是活动者所做的那些事情）之间的关系，一般适用于小型项目或大中型项目的模块级需求分析，对大中型项目的整体需求分析，实际上是一个非常复杂、有机结合的多个过程的系统，以后有机会我们再探讨。 [...]]]></description>
			<content:encoded><![CDATA[<p>Hello，时隔半年，我终于继续了 =.=</p>
<h2>1、为什么要观察你的项目&#8211;需求的重要性。</h2>
<p>俗话说，磨刀不误砍柴工，当开始一个项目时，我希望你就像在街上看到了美女，你要先好好打量打量，然后再思考，“啊，我怎么去问她的电话呢~”</p>
<p>So,same as our projects.</p>
<p>当开始一个项目时，你应当首先审视的是项目的需求，要注意了，除非是你自己为自己闲着没事做的东西，其他的项目，都是为别人做的，怎么理解呢，我的意思是说，你项目的目的就是满足别人的需求。软件实际上是一种商品。所谓商品，就是商品是为交换而生产（或用于交换）的对他人或社会有用的劳动产品[<a href="http://baike.baidu.com/view/68843.htm" target="_blank">百度百科</a>]。请注意“对他人或社会有用”，这就是在讲，我们所编写的软件是为了满足需求而存在的，如果不能满足需求，哪怕你用了再高的技术，软件做的再漂亮，运行效率再高，都不能被称之为一款合格的软件。</p>
<p>为什么突然要扯这么远呢，是因为，我曾经和很多人一样，在做开发的时候，开始的时候无时不刻的都在想，这个东西有什么技术创新点，什么地方的效率会很低，应该解决，后来我听到了一句话，叫做“过早优化是万恶之源（premature optimization is the root of all evil&#8211;<a href="http://en.wikipedia.org/wiki/Donald_Knuth" target="_blank">Donald Knuth</a>）”，可能的确有那样一些项目，他们要求很高的效率，或者，该项目的需求者一直在询问你关于效率的问题，但是无论如何，在你什么都没有的时候，你就什么都不能做，就像你并没有一个女儿，你却时刻想着如何去打扮她一样毫无意义。</p>
<p>请记住，我们所编写的软件，它的第一要务是满足需求，当然，运行效率、界面美化可能是需求的一部分（非功能性需求，我们稍后会谈到），但是请将其作为需求考虑，而不是贯穿软件的全部。</p>
<p>关于需求，这里有一幅漫画，来源未知（提示：你可以点击图片放大）：<br />
<a href="http://picasaweb.google.com/lh/photo/TDuCZ-g51Jx6Bry-m9D6vQ?feat=embedwebsite"><img src="http://lh3.ggpht.com/_OkD473b7axo/Si08GNdByVI/AAAAAAAAAic/mqkDFXeLXsg/s400/8bdbce98-4d20-3784-891b-a3d4f0970df3.jpg" alt="" /></a></p>
<p>另外还有此图片的中文版：http://picasaweb.google.com/lh/photo/ZK59I5p5-jfsc7kl213htQ?feat=directlink</p>
<h2>2、我要观察到什么&#8211;什么是需求</h2>
<p><em>“需求是产品必须完成的事以及必须具备的品质。需求存在的原因要么是该类型的产品要求一定的功能和品质，要么是客户希望需求成为交付的产品的一部分。”</em></p>
<p style="text-align: right;"><em>&#8211;《掌握需求过程》ISBN:9787115159830</em></p>
<p style="text-align: left;">从上面的漫画中，可以很有趣的发现，由于沟通方式，对目标的理解差异和技术水平的不同，都会让需求在传递中发生变化，这种变化有时可能是致命的，我们人类在沟通时多采用语言，然而语言，尤其是口头语言，极易发生变化。因此，就需要大家对需求有一个统一的认识，什么是需求，需求应该包括哪些内容，不应该包括哪些内容，应该如何去分析需求。</p>
<p style="text-align: left;">本节引言中的话，严格来讲不是对需求的定义，让我们来看IEEE软件工程标准词汇表(1997年)中“需求”的定义：</p>
<p>(1)用户解决问题或达到目标所需的条件或权能(Capability)。</p>
<p>(2)系统或系统部件要满足合同、标准、规范或其它正式规定文档所需具有的条件或权能。</p>
<p>(3)一种反映上面(1)或(2)所描述的条件或权能的文档说明</p>
<p>软件需求包括三个不同的层次—业务需求、用户需求和功能需求—也包括非功能需求。业务需求( business requirement)反映了组织机构或客户对系统、产品高层次的目标要求，它们在项目视图与范围文档中予以说明。用户需求(user requirement) 文档描述了用户使用产品必须要完成的任务，这在使用实例(use case)文档或方案脚本(scenario)说明中予以说明。功能需求(functional requirement)定义了开发人员必须实现的软件功能，使得用户能完成他们的任务，从而满足了业务需求。所谓特性(feature)是指逻辑上相关 的功能需求的集合，给用户提供处理能力并满足业务需求。</p>
<p>简单来说，需求就是说明你软件将要满足的用户需要，需求是你软件的功能列表，这里的功能可能包括看得见的功能和看不见的功能。同时需要注意实际用户（用户是重要的需求分析参与者，难以想象一个只有开发者而没有用户参与的需求分析，所得出的是什么）可能对需求的理解有误，有时他们甚至不了解活无法向你描述出他的需求，也有时，他会“啰啰嗦嗦”的向你讲一堆不是需求的东西。</p>
<p>同时，需求还包括非功能的部分，例如，“单次搜索查询必须在0.1秒内完成”、“用户传输文件的速度不应低于其网络最高可用带宽的50%”，这些内容并非软件的功能性要求，但是实际上是软件的使用者使用软件体验、感受的重要感受点甚至是其是否能完成功能性需求的制约。</p>
<h2>3、我没有马王爷的第三只眼&#8211;那么我如何分析需求呢</h2>
<p>哦，这很麻烦，是的，好吧，我们退一步，作为开发人员，你可以让你的产品经理去和客户打交道，但是你必须和你的产品经理打交道，同时，你还必须和你的代码打交道。</p>
<p>与产品经理打交道和与代码打交道是两码事，八杆子打不到一块，你不能和产品经理讲if(xxx)  {} ，也不能去问你的代码，这里是让用户操作的，还是你丫自动操作的。</p>
<p>在与产品人员打交道时，你有责任用他们的语言来描述问题，这并不是单纯为了对方能够听懂你说什么，更重要的是，这会大大减少你们在交流沟通中的误解。所以，熟知你所在的行业，熟悉他们的业务，如果你要开发财务系统，请去阅读财会相关书籍，如果你要开发ERP系统，请去和工人师傅、基层管理人员多聊聊，在拓展你领域的同时，也会让你对你的编程思想有新的看法。</p>
<p>在与代码打交道的时候，你需要是一个好的建筑师，你应当构建严谨、运行健壮、可扩展性强的代码，这要求你在充分理解需求的情况下，看到需求的发展方向以及需求中可能发生变动的情况，甚至你需要和产品经理、客户去沟通，提出你的想法，当你问道“我觉得这里这样做的话，系统可能存在不稳定的因素，如果怎么怎么样做，不仅系统稳定了，您的操作也会更方便”，客户恍然大悟，你又减轻了工作量，何乐不为呢。</p>
<p>在理解需求、分析系统时，我建议你首先这样做：</p>
<p><strong>将系统中存在的活动者都列出来，然后依次列出他们的操作功能和反应。</strong></p>
<p>比如，一个简单的文章系统，我们可能这样去描述它</p>
<div style="background:#EEE">普通用户：注册、登录、找回密码、修改个人信息、查看类别、查看文章、查看某个类别下的文章、输入关键字搜索文章、发表评论、当别人发表对自己评论的回复时收到邮件。<br />
管理员：查看用户信息、CURD（Create-Update-Read-Delete）类别、CURD文章</div>
<p>在上面的需求描述中，涉及了两个活动者，分别是“普通用户”和“管理员”，同时两个活动者都有若干功能，其中“普通用户”的“当别人发表对自己评论的回复时收到邮件”实际上不是用户的主动操作，而是用户对某个操作的反应，需要注意的是，这样的信息也需要在需求分析中体现。</p>
<p>需求分析可以体现为UML用例图，其好处是更直观，同时由于是统一化的表达，更有助于沟通，其他程序员可以更方便的理解你的意思，而不容易出现理解误差。</p>
<p>关于UML用例图方面的内容，可以到http://hi.baidu.com/jyangstu/blog/item/5d2f89131ef270c6c3fd7833.html查看一份简介。</p>
<p>我的需求方法实际上是用例图的一个超级简版，这个方法不能体现活动者与活动者、用例与用例（就是活动者所做的那些事情）之间的关系，一般适用于小型项目或大中型项目的模块级需求分析，对大中型项目的整体需求分析，实际上是一个非常复杂、有机结合的多个过程的系统，以后有机会我们再探讨。</p>
<h3  class="related_post_title">相关内容</h3><ul class="related_post"><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-3" title="听小韩聊PHP项目开发(3)–切分你的系统">听小韩聊PHP项目开发(3)–切分你的系统</a></li><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-1" title="听小韩聊PHP项目开发(1)&#8211;开题的话">听小韩聊PHP项目开发(1)&#8211;开题的话</a></li><li><a href="http://www.hanguofeng.cn/archives/security/configure-fast-in-lamp-on-windows-with-xampp" title="Windows下AMP平台配置FastCGI方法（以xampp为基础）">Windows下AMP平台配置FastCGI方法（以xampp为基础）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.hanguofeng.cn/archives/web-server/php-project-development-2/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<series:name><![CDATA[听小韩聊PHP项目开发]]></series:name>
	</item>
		<item>
		<title>Windows下AMP平台配置FastCGI方法（以xampp为基础）</title>
		<link>http://www.hanguofeng.cn/archives/security/configure-fast-in-lamp-on-windows-with-xampp?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=configure-fast-in-lamp-on-windows-with-xampp</link>
		<comments>http://www.hanguofeng.cn/archives/security/configure-fast-in-lamp-on-windows-with-xampp#comments</comments>
		<pubDate>Fri, 13 Feb 2009 09:12:45 +0000</pubDate>
		<dc:creator>hanguofeng</dc:creator>
				<category><![CDATA[Web服务器端技术]]></category>
		<category><![CDATA[电子商务]]></category>
		<category><![CDATA[网络安全]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.hanguofeng.cn/?p=95</guid>
		<description><![CDATA[一、配置Apache部分。 配置httpd.conf文件 在根配置节加入： LoadModule fcgid_module modules/mod_fcgid.so DefaultInitEnv PHPRC "D:/xampp/php/" DefaultInitEnv PATH "D:/xampp/php;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;" DefaultInitEnv SystemRoot "C:/Windows" DefaultInitEnv SystemDrive "C:" DefaultInitEnv TEMP "C:/WINDOWS/TEMP" DefaultInitEnv TMP "C:/WINDOWS/TEMP" DefaultInitEnv windir "C:/WINDOWS" AddHandler fcgid-script .php 其中“D:/xampp/php”为你的PHP所在目录。 在网站配置节中加入 FCGIWrapper "D:/xampp/php/php-cgi.exe" .php 二、配置PHP部分。 复制xampp/apache/bin/php.ini到xampp/php目录替换 三、配置应用程序部分。 以ThinkPHP框架为例 原.htaccess文件的： RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] 改为 RewriteRule ^(.*)$ index.php?s=$1 [QSA,PT,L] 四、常见错误处理 连接MYSQL时出现Can’t create TCP/IP socket (10106) [...]]]></description>
			<content:encoded><![CDATA[<p><span id="more-95"></span></p>
<h2>一、配置Apache部分。</h2>
<p>配置httpd.conf文件<br />
在根配置节加入：<br />
<code><br />
LoadModule fcgid_module modules/mod_fcgid.so<br />
DefaultInitEnv PHPRC "D:/xampp/php/"<br />
DefaultInitEnv PATH "D:/xampp/php;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;"<br />
DefaultInitEnv SystemRoot "C:/Windows"<br />
DefaultInitEnv SystemDrive "C:"<br />
DefaultInitEnv TEMP "C:/WINDOWS/TEMP"<br />
DefaultInitEnv TMP "C:/WINDOWS/TEMP"<br />
DefaultInitEnv windir "C:/WINDOWS"<br />
AddHandler fcgid-script .php<br />
</code><br />
其中“<strong>D:/xampp/php</strong>”为你的PHP所在目录。</p>
<p>在网站配置节中加入<br />
<code><br />
FCGIWrapper "D:/xampp/php/php-cgi.exe" .php<br />
</code></p>
<h2>二、配置PHP部分。</h2>
<p>复制xampp/apache/bin/php.ini到xampp/php目录替换</p>
<h2>三、配置应用程序部分。</h2>
<p>以ThinkPHP框架为例<br />
原.htaccess文件的：<br />
<code><br />
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]<br />
</code><br />
改为<br />
<code><br />
RewriteRule ^(.*)$ index.php?s=$1 [QSA,PT,L]<br />
</code></p>
<h2>四、常见错误处理</h2>
<h3>连接MYSQL时出现Can’t create TCP/IP socket (10106)</h3>
<p>检查httpd.conf文件中<br />
<code><br />
DefaultInitEnv PHPRC "D:/xampp/php/"<br />
DefaultInitEnv PATH "D:/xampp/php;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;"<br />
DefaultInitEnv SystemRoot "C:/Windows"<br />
DefaultInitEnv SystemDrive "C:"<br />
DefaultInitEnv TEMP "C:/WINDOWS/TEMP"<br />
DefaultInitEnv TMP "C:/WINDOWS/TEMP"<br />
DefaultInitEnv windir "C:/WINDOWS"<br />
</code><br />
保证里面的目录信息都是正确的就可以</p>
<h3>.htaccess 中Rewrite规则有问题</h3>
<p>Fastcgi模式下，不支持rewrite的目标网址的PATH_INFO的解析，例如<br />
<code><br />
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]<br />
</code><br />
转向的目标地址是index.php/Module/Action，则fastcgi会当作实际的目录查找而并非解析index.php文件，所以要根据程序支持将其修改为类似<br />
<code>RewriteRule ^(.*)$ index.php?s=$1 [QSA,PT,L]</code></p>
<hr />以下内容在2009-2-14 补充</p>
<hr />如果发现PhpMyAdmin访问不了，可以打开xampp/apache/conf/extra/httpd-xampp.conf文件，在<br />
<code><br />
&lt;Directory "D:/xampp/phpMyAdmin"&gt;<br />
</code><br />
一节中加入<br />
<code><br />
&lt;FilesMatch .php$&gt;<br />
SetHandler application/x-httpd-php<br />
&lt;/FilesMatch&gt;<br />
</code></p>
<h3  class="related_post_title">相关内容</h3><ul class="related_post"><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-3" title="听小韩聊PHP项目开发(3)–切分你的系统">听小韩聊PHP项目开发(3)–切分你的系统</a></li><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-2" title="听小韩聊PHP项目开发(2)&#8211;观察你的项目">听小韩聊PHP项目开发(2)&#8211;观察你的项目</a></li><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-1" title="听小韩聊PHP项目开发(1)&#8211;开题的话">听小韩聊PHP项目开发(1)&#8211;开题的话</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.hanguofeng.cn/archives/security/configure-fast-in-lamp-on-windows-with-xampp/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>听小韩聊PHP项目开发(1)&#8211;开题的话</title>
		<link>http://www.hanguofeng.cn/archives/web-server/php-project-development-1?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=php-project-development-1</link>
		<comments>http://www.hanguofeng.cn/archives/web-server/php-project-development-1#comments</comments>
		<pubDate>Sun, 28 Dec 2008 13:30:12 +0000</pubDate>
		<dc:creator>hanguofeng</dc:creator>
				<category><![CDATA[Web服务器端技术]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[听小韩聊PHP项目开发]]></category>

		<guid isPermaLink="false">http://www.hanguofeng.cn/?p=88</guid>
		<description><![CDATA[PHP是一个轻盈的、快捷的和强大的网站程序解决方案，它良好的完成了分析请求并对服务器资源进行调用的工作。 PHP是目前网上最流行的Web开发语言之一，据TIBOE的世界编程语言统计来看，从2001年到2008年，PHP的排行最低为10名，人数比例为1.37%，最高为第4名，比例为11.45%，你可以点击这里链接来查看此信息。 同时，PHP也在快速的发展中，从最早期的处理表单的CGI程序，逐渐增加特性，它已经成长为一个完善的面向对象的编程语言，同时内置和扩展库提供了大量的使用函数集，你可以使用这些函数集完成大量的常见工作。PHP有基本完善的面向对象语法，你可以使用大部分面向对象的概念，来实现各种设计模式和代码组织，以帮助你完成大型项目。 基于这样一些原因，在一段时间之前，我开始尝试使用PHP进行Web开发，然而最早开发的不是常见的网站，而是B/S的应用程序，继而又开发了一些网站，在这个过程中，我尝试了各种框架，也学着去评估效率，可维护性和可扩展性等多个因素，并予以实现在各个项目中。 我在进行PHP项目的开发中，逐渐总结了一些心得，包括PHP语言本身，但更多的是在项目中来看待PHP的开发，项目开发是一个很有趣的事情，在此，我们不仅要考虑功能的实现，还要考虑更多的诸如可扩展性、健壮性、与团队的合作等事情，这些经验会逐步和你们探讨和交流，这个专题正是基于此而撰写的。 这个专题，我的计划是总体由浅入深，而在具体的文章排序上不拘泥于顺序，而更像我的笔记，连载长度和时间也没有约束，所以建议您能够订阅我的RSS来获得最近的更新。 韩国峰 2008-12-28 相关内容听小韩聊PHP项目开发(3)–切分你的系统听小韩聊PHP项目开发(2)&#8211;观察你的项目Windows下AMP平台配置FastCGI方法（以xampp为基础）]]></description>
			<content:encoded><![CDATA[<p>PHP是一个轻盈的、快捷的和强大的网站程序解决方案，它良好的完成了分析请求并对服务器资源进行调用的工作。</p>
<p>PHP是目前网上最流行的Web开发语言之一，据TIBOE的世界编程语言统计来看，从2001年到2008年，PHP的排行最低为10名，人数比例为1.37%，最高为第4名，比例为11.45%，你可以<a href="http://www.tiobe.com/index.php/paperinfo/tpci/PHP.html" target="_blank">点击这里</a>链接来查看此信息。</p>
<p>同时，PHP也在快速的发展中，从最早期的处理表单的CGI程序，逐渐增加特性，它已经成长为一个完善的面向对象的编程语言，同时内置和扩展库提供了大量的使用函数集，你可以使用这些函数集完成大量的常见工作。PHP有基本完善的面向对象语法，你可以使用大部分面向对象的概念，来实现各种设计模式和代码组织，以帮助你完成大型项目。</p>
<p>基于这样一些原因，在一段时间之前，我开始尝试使用PHP进行Web开发，然而最早开发的不是常见的网站，而是B/S的应用程序，继而又开发了一些网站，在这个过程中，我尝试了各种框架，也学着去评估效率，可维护性和可扩展性等多个因素，并予以实现在各个项目中。</p>
<p>我在进行PHP项目的开发中，逐渐总结了一些心得，包括PHP语言本身，但更多的是在项目中来看待PHP的开发，项目开发是一个很有趣的事情，在此，我们不仅要考虑功能的实现，还要考虑更多的诸如可扩展性、健壮性、与团队的合作等事情，这些经验会逐步和你们探讨和交流，这个专题正是基于此而撰写的。</p>
<p>这个专题，我的计划是总体由浅入深，而在具体的文章排序上不拘泥于顺序，而更像我的笔记，连载长度和时间也没有约束，所以建议您能够订阅我的RSS来获得最近的更新。</p>
<p style="text-align: right;">韩国峰<br />
2008-12-28</p>
<h3  class="related_post_title">相关内容</h3><ul class="related_post"><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-3" title="听小韩聊PHP项目开发(3)–切分你的系统">听小韩聊PHP项目开发(3)–切分你的系统</a></li><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-2" title="听小韩聊PHP项目开发(2)&#8211;观察你的项目">听小韩聊PHP项目开发(2)&#8211;观察你的项目</a></li><li><a href="http://www.hanguofeng.cn/archives/security/configure-fast-in-lamp-on-windows-with-xampp" title="Windows下AMP平台配置FastCGI方法（以xampp为基础）">Windows下AMP平台配置FastCGI方法（以xampp为基础）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.hanguofeng.cn/archives/web-server/php-project-development-1/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<series:name><![CDATA[听小韩聊PHP项目开发]]></series:name>
	</item>
		<item>
		<title>EMAIL到你的Web程序&#8211;有趣的Email2HTTP</title>
		<link>http://www.hanguofeng.cn/archives/web-server/email2http?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=email2http</link>
		<comments>http://www.hanguofeng.cn/archives/web-server/email2http#comments</comments>
		<pubDate>Fri, 12 Sep 2008 14:27:51 +0000</pubDate>
		<dc:creator>hanguofeng</dc:creator>
				<category><![CDATA[Web服务器端技术]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.hanguofeng.cn/?p=30</guid>
		<description><![CDATA[大家一定都体验过通过Email使用Web程序吧，什么？你还没有？那么一定是你不记得了。 Flickr可以通过Email上传文件，Google Doc可以通过Email发送文件到指定收件箱从而完成文档的转换，这些都是通过Email使用Web的例子，如果这些你都没有试用过，那么你也许用到过彩信发表照片吧，在饭否、叽歪这样的微博客网站，都是对用户体验很好的例子。 上面所说的这些，在Web服务器端都是通过对Email读取来完成的，那么设想，提供这样一个特色服务，就需要搭建一个邮件服务器来收取邮件，对于大多数程序员和个人站长来说，都是一个门槛很高的操作，而现在，有了Email2HTTP，你完全不用担心了。 Email2HTTP正式这样一个服务的提供商：它为你提供了一个可以接收邮件并将邮件内容以HTTP协议POST到你指定的CallBack地址，让你给你的网站加上这些有趣功能的服务。 如下是Email2HTTP官方给出的一段读取邮件的代码，他接受Email2HTTP服务器转发来的请求，保存其中的文件，并输出邮件内容。  [snippet=8368] 相关内容听小韩聊PHP项目开发(3)–切分你的系统听小韩聊PHP项目开发(2)&#8211;观察你的项目Windows下AMP平台配置FastCGI方法（以xampp为基础）]]></description>
			<content:encoded><![CDATA[<p>大家一定都体验过通过Email使用Web程序吧，什么？你还没有？那么一定是你不记得了。</p>
<p>Flickr可以通过Email上传文件，Google Doc可以通过Email发送文件到指定收件箱从而完成文档的转换，这些都是通过Email使用Web的例子，如果这些你都没有试用过，那么你也许用到过彩信发表照片吧，在饭否、叽歪这样的微博客网站，都是对用户体验很好的例子。</p>
<p><span id="more-30"></span></p>
<p>上面所说的这些，在Web服务器端都是通过对Email读取来完成的，那么设想，提供这样一个特色服务，就需要搭建一个邮件服务器来收取邮件，对于大多数程序员和个人站长来说，都是一个门槛很高的操作，而现在，有了Email2HTTP，你完全不用担心了。</p>
<p><a href="https://www.email2http.com/">Email2HTTP</a>正式这样一个服务的提供商：它为你提供了一个可以接收邮件并将邮件内容以HTTP协议POST到你指定的CallBack地址，让你给你的网站加上这些有趣功能的服务。</p>
<p>如下是Email2HTTP官方给出的一段读取邮件的代码，他接受Email2HTTP服务器转发来的请求，保存其中的文件，并输出邮件内容。</p>
<p> <code>[snippet=8368]</code></p>
<h3  class="related_post_title">相关内容</h3><ul class="related_post"><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-3" title="听小韩聊PHP项目开发(3)–切分你的系统">听小韩聊PHP项目开发(3)–切分你的系统</a></li><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-2" title="听小韩聊PHP项目开发(2)&#8211;观察你的项目">听小韩聊PHP项目开发(2)&#8211;观察你的项目</a></li><li><a href="http://www.hanguofeng.cn/archives/security/configure-fast-in-lamp-on-windows-with-xampp" title="Windows下AMP平台配置FastCGI方法（以xampp为基础）">Windows下AMP平台配置FastCGI方法（以xampp为基础）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.hanguofeng.cn/archives/web-server/email2http/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Beyond summer</title>
		<link>http://www.hanguofeng.cn/archives/life/beyond-summer?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=beyond-summer</link>
		<comments>http://www.hanguofeng.cn/archives/life/beyond-summer#comments</comments>
		<pubDate>Thu, 14 Aug 2008 15:17:27 +0000</pubDate>
		<dc:creator>hanguofeng</dc:creator>
				<category><![CDATA[生活感悟]]></category>
		<category><![CDATA[ChinaPub]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[北京]]></category>

		<guid isPermaLink="false">http://www.hanguofeng.cn/?p=23</guid>
		<description><![CDATA[在ChinaPub工作一个月了，特意上来写点什么，记录和汇报一下。 前两天装上了Ubuntu，用wubi装的，原因是我实在没有足够的硬盘空间再分给Ubuntu了，当然也没有胆量尝试下从来没有熟练做过的Ubuntu分区。其实接触Linux系统也不晚，记得还在高二的时候就费劲八叱的在家里的电脑上装Redhat了，三张盘，对，这还是受了老牛的影响，那大哥买了个“正版”的Redhat。后来又找外教Marian借了正版的说明书来看。 Marian是一个很有趣的胖女孩，多胖呢，顶我一个半吧，她和我们讲，I use Linux because it&#8217;s free!，她讲课的时候还一边在电脑上打出自己说得话，用投影放出来，生怕我们听不懂，很周到，人家的打字速度，那真叫一个快啊，呵呵，扯远了。 LinuxQQ实在不如想象中的好用，虽然比得Pidgin来说，它的确很QQ，但是不能发图不能发文件，连自定义表情也发不了，这的确有点恶心，还是不是的卡死Linux，OMG。 现在一个人在做“期望负载量很大”的站点，架构，编码，数据库设计，还有JS，有些吃力了，用ThinkPHP框架，还好，算是减轻了不少的工作量，现在倒是很好奇林老师的CoffeePHP了，做B/S系统的PHP框架，呵呵。 最后学小女生，附图一张 相关内容听小韩聊PHP项目开发(3)–切分你的系统听小韩聊PHP项目开发(2)&#8211;观察你的项目北海公园游记]]></description>
			<content:encoded><![CDATA[<p>在ChinaPub工作一个月了，特意上来写点什么，记录和汇报一下。<span id="more-23"></span></p>
<p>前两天装上了Ubuntu，用wubi装的，原因是我实在没有足够的硬盘空间再分给Ubuntu了，当然也没有胆量尝试下从来没有熟练做过的Ubuntu分区。其实接触Linux系统也不晚，记得还在高二的时候就费劲八叱的在家里的电脑上装Redhat了，三张盘，对，这还是受了老牛的影响，那大哥买了个“正版”的Redhat。后来又找外教Marian借了正版的说明书来看。</p>
<p>Marian是一个很有趣的胖女孩，多胖呢，顶我一个半吧，她和我们讲，I use Linux because it&#8217;s free!，她讲课的时候还一边在电脑上打出自己说得话，用投影放出来，生怕我们听不懂，很周到，人家的打字速度，那真叫一个快啊，呵呵，扯远了。</p>
<p>LinuxQQ实在不如想象中的好用，虽然比得Pidgin来说，它的确很QQ，但是不能发图不能发文件，连自定义表情也发不了，这的确有点恶心，还是不是的卡死Linux，OMG。</p>
<p>现在一个人在做“期望负载量很大”的站点，架构，编码，数据库设计，还有JS，有些吃力了，用ThinkPHP框架，还好，算是减轻了不少的工作量，现在倒是很好奇林老师的CoffeePHP了，做B/S系统的PHP框架，呵呵。</p>
<p>最后学小女生，附图一张<br />
<a href="http://picasaweb.google.com/hanguofeng/TShirts/photo?authkey=yqmYoJbh_VY#5234392214377902546"><img src="http://lh5.ggpht.com/hanguofeng/SKRL_GkQsdI/AAAAAAAAAOU/pac-Rr6Sih8/s400/IMG_2450.jpg" alt="" /></a></p>
<h3  class="related_post_title">相关内容</h3><ul class="related_post"><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-3" title="听小韩聊PHP项目开发(3)–切分你的系统">听小韩聊PHP项目开发(3)–切分你的系统</a></li><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-2" title="听小韩聊PHP项目开发(2)&#8211;观察你的项目">听小韩聊PHP项目开发(2)&#8211;观察你的项目</a></li><li><a href="http://www.hanguofeng.cn/archives/life/beihai-park" title="北海公园游记">北海公园游记</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.hanguofeng.cn/archives/life/beyond-summer/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>PHP串行化与JSON</title>
		<link>http://www.hanguofeng.cn/archives/web-server/php-serialize-json?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=php-serialize-json</link>
		<comments>http://www.hanguofeng.cn/archives/web-server/php-serialize-json#comments</comments>
		<pubDate>Wed, 19 Mar 2008 07:28:11 +0000</pubDate>
		<dc:creator>hanguofeng</dc:creator>
				<category><![CDATA[Web服务器端技术]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.hanguofeng.cn/archives/web-server/php-serialize-json</guid>
		<description><![CDATA[Ok，各位亲爱的朋友，让我们开始这个新概念的旅程，串行化这个话题可能大家以前都没有多加关注，事情其实起源于那天我随便翻翻PHP手册，发现这个串行化的函数，之后闲来无聊又做一个WordPress的插件，这个时候顺便用了一下串行化，发现在某些场合的确非常方便。

先来解释下串行化：简单来说，串行化即将变量转换成字节流的过程。串行化的提出，有效的解决了对象的保存和传输的问题，举例来说，我在JavaScript中建立了一个对象，我现在想将这个对象保存到服务器端的数据库中，那么我如何进行操作呢，这个时候往往就用到了对象的串行化。在JavaScript的串行化中不得不提JSON，JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写，同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式，但是也使用了类似于C语言家族的习惯（包括C, C++, C#, Java, JavaScript, Perl, Python等）。这些特性使JSON成为理想的数据交换语言。]]></description>
			<content:encoded><![CDATA[<p>作者：hanguofeng[小韩]</p>
<p>发布于：经典论坛 玄猫的窝（作者的博客）</p>
<p>在经典论坛的连载地址：<a href="http://bbs.blueidea.com/thread-2838888-1-1.html">http://bbs.blueidea.com/thread-2838888-1-1.html</a></p>
<p>在作者博客的连载地址：<a href="http://www.hanguofeng.cn/archives/web-server/php-serialize-json">http://www.hanguofeng.cn/archives/web-server/php-serialize-json</a></p>
<p>本文Word完整版：<a href="http://docs.google.com/Doc?id=ajd3pzcpcjzg_22gpwvxshs">http://docs.google.com/Doc?id=ajd3pzcpcjzg_22gpwvxshs</a></p>
<p>本文遵从<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" target="_blank">创作共用协议</a>（by-nc-sa）</p>
<p><span id="more-10"></span></p>
<h1>What 、Why、How</h1>
<h2>What</h2>
<p>Ok，各位亲爱的朋友，让我们开始这个新概念的旅程，串行化这个话题可能大家以前都没有多加关注，事情其实起源于那天我随便翻翻PHP手册，发现这个串行化的函数，之后闲来无聊又做一个WordPress的插件，这个时候顺便用了一下串行化，发现在某些场合的确非常方便。</p>
<p>先来解释下串行化：简单来说，串行化即将变量转换成字节流的过程。串行化的提出，有效的解决了对象的保存和传输的问题，举例来说，我在JavaScript中建立了一个对象，我现在想将这个对象保存到服务器端的数据库中，那么我如何进行操作呢，这个时候往往就用到了对象的串行化。在JavaScript的串行化中不得不提JSON，JSON(JavaScript<br />
Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写，同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition &#8211; December<br />
1999的一个子集。 JSON采用完全独立于语言的文本格式，但是也使用了类似于C语言家族的习惯（包括C, C++, C#, Java, JavaScript, Perl, Python等）。这些特性使JSON成为理想的数据交换语言。</p>
<p>人们通常将JSON和XML进行比较，二者都是将对象扁平化（稍后我们解释这个&#8221;扁平化&#8221;）的一种手段，XML的特点是结构严谨，而JSON的特点则是简单易读、容易使用程序进行分析，因为它能够很简单的将一个对象转换为一个字符流的形式，例如如下代码：</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;human&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;hanguofeng&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;age&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">22</span><span style="color: #009900;">&#125;</span></pre></div></div>

<p>则是一个JSON表达式，他保存了一个对象，我们如何将它恢复为对象呢？很简单，如下：</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> animal_str <span style="color: #339933;">=</span> <span style="color: #3366CC;">'{&quot;type&quot;:&quot;human&quot;,&quot;name&quot;:&quot;hanguofeng&quot;,&quot;age&quot;:22}'</span><span style="color: #339933;">;</span> 
&nbsp;
我们通过JavaScript的求值函数，将JSON表达式进行运算，并返回值，用以获得一个对象，到这里，我想你一定会和我一样，对JSON格式的创造者的思维佩服不已吧。
&nbsp;
本来说讲串行化的，<span style="color: #3366CC;">&quot;不小心&quot;</span>谈到JSON，并且讲了这么多，呵呵，跑题了吗？没有，PHP的串行化和JSON是非常像的，一个PHP的串行化表达式如下：</pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">a<span style="color: #339933;">:</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">:</span><span style="color: #009900;">&#123;</span>s<span style="color: #339933;">:</span><span style="color: #cc66cc;">4</span><span style="color: #339933;">:</span><span style="color: #0000ff;">&quot;type&quot;</span><span style="color: #339933;">;</span>s<span style="color: #339933;">:</span><span style="color: #cc66cc;">5</span><span style="color: #339933;">:</span><span style="color: #0000ff;">&quot;human&quot;</span><span style="color: #339933;">;</span>s<span style="color: #339933;">:</span><span style="color: #cc66cc;">4</span><span style="color: #339933;">:</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #339933;">;</span>s<span style="color: #339933;">:</span><span style="color: #cc66cc;">10</span><span style="color: #339933;">:</span><span style="color: #0000ff;">&quot;hanguofeng&quot;</span><span style="color: #339933;">;</span>s<span style="color: #339933;">:</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">:</span><span style="color: #0000ff;">&quot;age&quot;</span><span style="color: #339933;">;</span>s<span style="color: #339933;">:</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">:</span><span style="color: #0000ff;">&quot;20&quot;</span><span style="color: #339933;">;</span><span style="color: #009900;">&#125;</span></pre></div></div>

<p>他看起来结构和JSON有些类似，实际上，这个表达式是如下数组的串行化结果：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$animal</span> <span style="color: #339933;">=</span>
<span style="color: #009900;">&#40;</span>
&nbsp;
<span style="color: #0000ff;">&quot;type&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;human&quot;</span><span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000ff;">&quot;name&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;hanguofeng&quot;</span><span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000ff;">&quot;age&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;20&quot;</span>
&nbsp;
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>OK，上面的一些介绍只是让你大致看到串行化和JSON是什么样的东西，你无须对这里的代码过分纠结，我们在后面会详细讲解的，下面我们来谈谈为什么要使用串行化。</p>
<h2>Why</h2>
<p>串行化首先是作为数据传输的方便而出现的，正如本文开始我提出的问题，我在JavaScript中建立了一个对象，我现在想将这个对象保存到服务器端的数据库中，应该如何做，这其实上是一个&#8221;我如何将一个对象从浏览器提交到服务器&#8221;的问题，在这个传输过程中，我们知道，实际上只能够传递字符流，字符流是一维（扁平）的，然而很多对象却是多维的，如果要传递的对象是一个字符串，那么很简单，我们直接将其作为传递的内容就可以了，如果要传递的对象是一个数组或者其他的结构呢，我们就需要用字符流来描述他，就比如在电话里面，我问你的名字是什么，你会告诉我，你的名字是张三、李四，而我问你，你的长相如何呢，你就需要用文字向我描述了，我们进行数据传递的媒介往往和这条电话线路一样，只能传递字符流，而我们描述对象的过程，实际上就是串行化的过程。</p>
<p>另外，串行化也可以用于对对象的持久化存储，也许你曾经也和我一样，想着在数据库的某一个字段中存储一个对象，现在我们可以非常简单的做到这一点，并且，你的这个数据库字段不需要设定为特殊格式，设定为varchar就可以了（当然，如果对象很大，你可能需要设定为text）。</p>
<h2>How</h2>
<h3>PHP串行化语法</h3>
<p>好了，我想What和Why的问题你都了解了，本节最后我们来讲点理论性强一些的内容，就是如何使用PHP串行化和反串行化数据，如何将JavaScript对象串行化（即变为JSON格式）和如何将其反串行化，最后则是如何将JSON和PHP的串行化建立关系。</p>
<p>PHP为我们提供了两个函数，用来进行串行化和反串行化的操作，这两个函数分别是：serialize()和unserialize()，他们适用于PHP4和PHP5，下面分别进行讲解：</p>
<p>serialize()</p>
<p>(PHP 4, PHP 5, PECL axis2:0.1.0-0.1.1)</p>
<p>serialize &#8211; 获得一个可存储的表述值</p>
<p>说明</p>
<p>string serialize ( mixed $value )</p>
<p>获得一个可存储的表述值</p>
<p>本函数用于无损的存储或者传递PHP变量值和结构。</p>
<p>如果需要将已经串行化的值转回PHP变量，可以使用unserialize()函数。</p>
<p>参数</p>
<p>value</p>
<p>即被串行化的表达式。serialize()处理除资源指针之外的所有类型，你甚至可以将含有指向自身元素的数组串行化。你串行化的含有循环指向的数组或者对象一样会被存储，其他的指向则会丢失。</p>
<p>当串行化对象时，PHP会尝试首先调用其成员函数__sleep()。这将允许对象在被串行化之前进行诸如最后的清理工作等。同样地，当使用unserialize()函数将对象恢复时，会调用成员函数__wakeup()。</p>
<p>返回值</p>
<p>返回一个可以被存储在任何地点的包含对象的字节流表达式的字符串。</p>
<p>unserialize()</p>
<p>(PHP 4, PHP 5, PECL axis2:0.1.0-0.1.1)</p>
<p>unserialize &#8211; 从一个已存储的表达式中获得一个PHP变量值</p>
<p>说明</p>
<p>mixed unserialize ( string $str )</p>
<p>unserialize()获取一个简单类型的串行化变量并将其转换回PHP变量值。</p>
<p>参数</p>
<p>str</p>
<p>串行化后的字符串</p>
<p>如果被反串行化的变量是一个对象，则成功恢复该对象的结构后，PHP将自动尝试执行该对象的__wakeup()成员函数（如果其存在）。</p>
<p>unserialize_callback_func指令：你可以设定在此过程中呗执行的回调函数，如果某个未被定义的类应当在反串行化时被实例化（以避免获得一个不完全的对象&#8221;__PHP_Incomplete_Class&#8221;）。你可以使用php.ini，ini_set()或者.htaccess来定义&#8221;unserialize_callback_func&#8221;。当一个未被定义的类被实例化时，它会被调用。屏蔽这个特性只需将其设为空即可。</p>
<p>返回值</p>
<p>返回转换后的数值，可能是布尔变量、实数、浮点数、字符串、数组或者对象。</p>
<p>假如传入的字符串不可以被反串行化，则返回FALSE，同时抛出NOTICE错误。</p>
<p>（以上译自PHP手册）</p>
<h3>PHP串行化实例</h3>
<p><strong>数组的串行化和反串行化</strong></p>
<p>OK，让我们来用实例学习一下，首先，请建立sample1.php文件，我们在这个文件中用如下语句来创建一个哈希数组：</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$animal</span> <span style="color: #339933;">=</span>
<span style="color: #009900;">&#40;</span>
<span style="color: #0000ff;">&quot;type&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;human&quot;</span><span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000ff;">&quot;name&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;hanguofeng&quot;</span><span style="color: #339933;">,</span>
&nbsp;
<span style="color: #0000ff;">&quot;age&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;20&quot;</span>
&nbsp;
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>为了测试这个数组的值，你可以使用print_r()函数来输出数组，输出的结果如下：</p>
<div><code><br />
Array</code></div>
<div><code>(</code></div>
<p><code>[type] =&gt; human</p>
<p>[name] =&gt; hanguofeng</p>
<p>[age] =&gt; 20</p>
<p>)</p>
<p> </p>
<p> </p>
<p></code></p>
<p>那么我们将他来串行化一下，串行化的代码如下：</p>
<div><code><br />
$animal =</code></div>
<div><code>array</code></div>
<p><code>(</p>
<p>"type" =&gt; "human",</p>
<p>"name" =&gt; "hanguofeng",</p>
<p>"age" =&gt; "20"</p>
<p>);</p>
<p>$animal_ser=serialize($animal);</p>
<p>echo($animal_ser);</p>
<p> </p>
<p> </p>
<p></code></p>
<p>这里我们将数组$animal串行化，将返回的串行化字符串保存在变量$animal_ser中，并输出，输出的结果是：</p>
<div><code><br />
a:3:{s:4:"type";s:5:"human";s:4:"name";s:10:"hanguofeng";s:3:"age";s:2:"20";}</code></div>
<div><code> </code></div>
<p><code> </p>
<p></code></p>
<p>我们来简单对这个字符串进行一个解析：</p>
<p>a:3表示这是一个数组型的对象(a)，他共有三个内置的对象(3)</p>
<p>大括号里面的部分是以逗号分割的对象表达式列表，以s:4:&#8221;type&#8221;为例，他表示一个字符串（s），长度为4位（4），值为&#8221;type&#8221;，即哈希数组的第一个元素的键。</p>
<p>后面的部分以此类推，我们不再赘述，你可以试试自己将各种对象串行化，看看串行化后的字符串是如何构建的。</p>
<p>下面来看数组的反串行化，即将我们上面生成的串行化字符串恢复为数组，代码如下：</p>
<div><code><br />
$animal_ser='a:3:{s:4:"type";s:5:"human";s:4:"name";s:10:"hanguofeng";s:3:"age";s:2:"20";}';</code></div>
<div><code>$animal = unserialize($animal_ser);</code></div>
<p><code>print_r($animal);</p>
<p> </p>
<p> </p>
<p></code></p>
<p>在第一行中，我们假设$animal_ser的值为上面获得的串行化字符串，在第二行将该字符串恢复为开始的数组，并赋值给$animal，最后输出$animal这个数组，此时的输出和本节开始时输出的原始数组是一样的，即：</p>
<div><code><br />
Array</code></div>
<div><code>(</code></div>
<p><code>[type] =&gt; human</p>
<p>[name] =&gt; hanguofeng</p>
<p>[age] =&gt; 20</p>
<p>)</p>
<p> </p>
<p> </p>
<p></code></p>
<p>这样我们就完成了数组的反串行化。</p>
<p><strong>拓展知识-自定义对象的串行化和反串行化</strong></p>
<p>对数组进行串行化是一个基础操作，然而在实际的程序设计中，我们可能经常对其他类型的变量进行串行化，例如对某个自定义对象进行串行化，这里有一个我们自己编写的类A（保存在classa.inc中）：</p>
<div><code><br />
class A {</code></div>
<div><code>var $one = 1;</code></div>
<p><code> </p>
<p></code></p>
<p>function show_one() {</p>
<p>echo $this-&gt;one;</p>
<p>}</p>
<p>}</p>
<p>我们在如下代码中创建类的实例并对该实例进行串行化：</p>
<div><code><br />
//省略引入classa.inc文件的代码</code></div>
<div><code>$a=new A;</code></div>
<p><code>echo(serialize($a));</p>
<p> </p>
<p> </p>
<p></code></p>
<p>此时输出的内容为：</p>
<div><code><br />
O:1:"A":1:{s:3:"one";i:1;}</code></div>
<div><code> </code></div>
<p><code> </p>
<p></code></p>
<p>总体来看，这个串行化字符串输出了改对象当前的状态，即i的值为1。下面我们来逐个分析其中的细节。</p>
<p>O:1：由于当前的变量是一个自定义对象，因此该表征字符为&#8221;O&#8221;，表示Object。</p>
<p>后面的&#8221;A&#8221;标识了该变量是哪个类的实例，这里即A类。</p>
<p>大括号内即该实例的各个属性的名称和值。</p>
<p>而后我们将其进行反串行化：</p>
<div><code><br />
//省略引入classa.inc文件的代码</code></div>
<div><code>include("classa.inc");</code></div>
<p><code>$s = 'O:1:"A":1:{s:3:"one";i:1;}';</p>
<p>$a = unserialize($s);</p>
<p>$a-&gt;show_one();</p>
<p> </p>
<p> </p>
<p></code></p>
<p>此时输出&#8221;1&#8243;，即调用了A类的show_one()方法。</p>
<p>你可以注意到虽然在实例的串行化字符串中并没有包含类的方法，但是我们将其反串行化后，仍然可以调用类的方法，这个特性在PHP4及以上版本中被支持（当然，你需要包含类的定义文件classa.inc）。</p>
<p>注：你可以参考PHP手册中Language Reference-&gt;Classes and Objects-&gt;Serializing objects &#8211; objects in sessions一节的内容。</p>
<h3>在JavaScript中串行化为JSON-使用json2.js</h3>
<p>JavaScript中没有直接串行化对象的内置方法，当然你可以自己写一个，不过我还是强烈推荐你在这里偷个小懒，使用现成的组件，JSON的官方网站<a href="&lt;br"></a> &#8220;http://www.json.org&#8221;&gt;www.json.org提供了对JavaScript对象实现JSON串行化的代码库-json2.js，你可以从这里获得它。</p>
<p>获得完毕json2.js文件后，你可以打开这个文件，在文件的前部分包含了相当大量的注释信息，如果你的英文足够好，那么你可以省略我这一节，参考该文件的注释就可以了，如果作为程序员，你已经看够了大片的字母，想看看我的汉字+字母，那你可以向下继续了。</p>
<p>简单的翻译下这个注释：</p>
<p>可参考<a href="http://www.JSON.org/js.html">http://www.JSON.org/js.html</a></p>
<p>该文件创建了一个包含两个方法的全局对象JSON，它的方法分别是：</p>
<div><code><br />
JSON.stringify(value, whitelist)</code></div>
<div><code> </code></div>
<p><code> </p>
<p></code></p>
<p>value 任意的JavaScript值，一般是一个对象或者数组</p>
<p>whitelist 一个可选的数组参数，用于判定对象值如何被串行化</p>
<p>这个方法通过一个JavaScript值来生成JSON文本。在进行串行化时，根据可选的参数whitelist，有三种可能：</p>
<p>如果某个对象有toJSON方法，那么则调用该方法，toJSON方法的返回值将被串行化。</p>
<p>否则，如果可选参数whitelist是一个数组，那么数组中的元素将被用来选择对象进行串行化时的的成员。</p>
<p>否则，如果没有使用whitelist参数，则对象的所有成员将被串行化。</p>
<p>如果值没有JSON的表现形式，例如undefined或者函数，则其不会被串行化。在对象中，这样的值会被忽略，而在数组中将会被null替换。</p>
<p>JSON.stringify(undefined)会返回undefined。日期将会被串行化为被引用的ISO日期。</p>
<p>例：</p>
<div><code><br />
var text = JSON.stringify(['e', {pluribus: 'unum'}]);</code></div>
<div><code>//text is '["e",{"pluribus":"unum"}]'</code></div>
<p><code> JSON.parse(text, filter)</p>
<p> </p>
<p> </p>
<p></code></p>
<p>该方法解析一个JSON文本，并生成一个组件或者数组，其可能抛出一个SyntaxError异常。</p>
<p>可选的filter参数是一个可过滤和转换结果的函数、它接受每个键和值，它的返回值用来替换源值。如果它返回所接收的值，那么结果不会被改变。如果他返回undefined，则该成员会被删除。</p>
<p>例：</p>
<div><code><br />
//解析文本，如果某个键包含字符串"date"，则将其值转换为日期</code></div>
<div><code>myData = JSON.parse(text, function (key, value) {</code></div>
<p><code>return key.indexOf('date') &gt;= 0 ? new Date(value) : value;</p>
<p>});</p>
<p> </p>
<p> </p>
<p></code></p>
<p>上面的入门教程已经使你基本了解了json2.js的使用方法，这里关于该文件我就不再赘述了，只是有一个小提示，如果你想简单的解析一个JSON文本，那么可以使用eval()函数，改函数是JavaScript的内置函数，例如解析在JSON.stringify的案例中生成的JSON文本，可以使用：</p>
<div><code><br />
var myE = eval('["e",{"pluribus":"unum"}]');</code></div>
<div><code> </code></div>
<p><code> </p>
<p></code></p>
<p>来获得对象myE。</p>
<h3>在JavaScript中串行化为JSON-使用prototype.js</h3>
<p>如果你和我一样，喜欢在自己的项目中使用开源的JavaScript框架，那么你可能可以省去使用json2.js文件了，这里以protype.js为例，该文件可以在<a href="&lt;br"></a> &#8220;http://www.prototypejs.org&#8221;&gt;http://www.prototypejs.org下载，由于本文不是在讲JavaScript框架，这里我假设你对prototype.js的使用已经有所了解了。</p>
<p>prototype.js中提供了对Object对象的toJSON方法，你可以使用Object.toJSON()方法来实现对对象的串行化，例如：</p>
<div><code><br />
var cat=</code></div>
<div><code>{</code></div>
<p><code>name:"hellokitty",</p>
<p>height:"6 apples"</p>
<p>}</p>
<p>alert(Object.toJSON(cat));</p>
<p>//将弹出对话框，内容为 {"name": "hellokitty", "height": "6 apples"}</p>
<p> </p>
<p> </p>
<p></code></p>
<p>另外，在prototype.js中还有另外的JSON支持，主要是在Ajax对象中对Ajax返回请求中JSON内容的解析。这里暂时与我们的内容无关，也不再介绍了。</p>
<h1>PHP与JSON</h1>
<p>在上面我们一起了解了PHP进行对象串行化的方法以及在JavaScript中进行将对象串行化为JSON的方法，你大致会质疑我为什么将二者放在一起，因为他们的语法实际是不完全一样的，然而，在PHP中，可以对JSON文本进行反串行化，也可以将PHP的对象串行化为JSON而非PHP风格的文本。这主要是靠json_decode和json_encode两个函数来完成的，需要特别说明的是，这两个函数在PHP<br />
5 &gt;= 5.2.0中才被支持，如果你要编写运行在PHP4环境下的程序，那么这两个函数是不可以使用的。</p>
<h2>json_decode函数</h2>
<p>语法</p>
<p>mixed json_decode ( string $json [, bool $assoc] )</p>
<p>获取一个JSON编码文本，并且将其转换为PHP变量</p>
<p>参数</p>
<p>json</p>
<p>被JSON编码的文本</p>
<p>assoc</p>
<p>当为TRUE时，返回的值为联合数组</p>
<p>返回值</p>
<p>返回一个对象，或者如果可选的assoc参数为TRUE，则一个联合数组将会被返回</p>
<h2>json_encode函数</h2>
<p>语法</p>
<p>string json_encode ( mixed $value )</p>
<p>该函数返回一个值的JSON表达式</p>
<p>参数</p>
<p>value</p>
<p>要被编码的值，可以为除resource外的任何类型参数</p>
<p>这个函数仅在UTF-8编码格式时起作用</p>
<p>返回值</p>
<p>当成功时返回编码后的JSON文本</p>
<h2>json_decode函数实例</h2>
<p>下面两个例子都基于我们的一个情景假设，即，我们有一个用户注册的模块，这个模块以&#8221;面向对象&#8221;的方式工作，在json_decode函数实例中，我们在前台将用户的注册信息变为一个类的属性，而后传递到后台的php文件（这里为了简便，就不用Ajax了）。在json_encode实例中，我们在html文件中引用一个js文件，地址指向php文件，在php文件中输出json编码后的用户对象（同样为了简便，我们直接生成一个对象而不从数据库中取信息），并在html中输出。</p>
<p>好了，先来看前台的页面json_encode.htm，这个页面模仿了通常的注册页面，在其上面有一个表单，当提交时，触发JavaScript函数，生成一个用户对象user，将表单内容设为用户对象的属性，生成JSON文本，以POST方式传递到后台的json_encode.php文件。在js_encode.php文件中，将JSON文本用json_decode函数解析为PHP对象，并输出。</p>
<p>好了，先来看json_encode.html文件，文件代码如下：</p>
<div><code><br />
……省略HTML头部,以下代码位于head标签</code></div>
<div><code>function JSON_test(o)</code></div>
<p><code>{</p>
<p>var user = {</p>
<p>name:document.getElementById('txt_name').value,</p>
<p>email:document.getElementById('txt_email').value,</p>
<p>password:document.getElementById('txt_name').value</p>
<p>}</p>
<p>var json_string = JSON.stringify(user);</p>
<p> </p>
<p></code></p>
<p>document.getElementById(&#8216;txt_json&#8217;).value=json_string;</p>
<p>alert(&#8220;点击确定后将提交表单&#8221;);</p>
<p>o.submit();</p>
<p>}</p>
<p>……以下代码位于body标签</p>
<p>&lt;form id=&#8221;form1&#8243; name=&#8221;form1&#8243; method=&#8221;post&#8221; action=&#8221;json_encode.php&#8221;<br />
onsubmit=&#8221;JSON_test(this)&#8221;&gt;</p>
<p>&lt;label for=&#8221;txt_name&#8221;&gt;姓名&lt;/label&gt;</p>
<p>&lt;p&gt;</p>
<p>&lt;input type=&#8221;text&#8221; name=&#8221;txt_name&#8221; id=&#8221;txt_name&#8221; /&gt;</p>
<p>&lt;/p&gt;</p>
<p>&lt;label for=&#8221;txt_email&#8221;&gt;邮箱&lt;/label&gt;</p>
<p>&lt;p&gt;</p>
<p>&lt;input type=&#8221;text&#8221; name=&#8221;txt_email&#8221; id=&#8221;txt_email&#8221; /&gt;</p>
<p>&lt;/p&gt;</p>
<p>&lt;p&gt;</p>
<p>&lt;label for=&#8221;txt_password&#8221;&gt;密码&lt;/label&gt;</p>
<p>&lt;/p&gt;</p>
<p>&lt;p&gt;</p>
<p>&lt;input type=&#8221;text&#8221; name=&#8221;txt_password&#8221; id=&#8221;txt_password&#8221; /&gt;</p>
<p>&lt;/p&gt;</p>
<p>&lt;p&gt;</p>
<p>&lt;input type=&#8221;text&#8221; name=&#8221;txt_json&#8221; id=&#8221;txt_json&#8221; /&gt;</p>
<p>&lt;label for=&#8221;button&#8221;&gt;&lt;/label&gt;</p>
<p>&lt;input type=&#8221;submit&#8221; name=&#8221;button&#8221; id=&#8221;button&#8221; value=&#8221;JSON&#8221; /&gt;</p>
<p>&lt;/p&gt;</p>
<p>&lt;/form&gt;</p>
<p>当提交表单时，将触发JavaScript函数JSON_text()，该函数首先建立一个JavaScript对象user，将其name、email和password属性分别设为对应表单的值，而后使用json2.js文件的JSON.stringify方法将其转换为JSON文本json_string，最后设定隐藏域（这里为了使你看的清楚，我把这个隐藏域以文本框形式显示了）txt_json的值为json_string，并提交表单。</p>
<p>下面到json_encode.php文件，如下：</p>
<div><code><br />
$json_string = $_POST["txt_json"];</code></div>
<div><code>if(ini_get("magic_quotes_gpc")=="1")</code></div>
<p><code>{</p>
<p>$json_string=stripslashes($json_string);</p>
<p>}</p>
<p>$user = json_decode($json_string);</p>
<p> </p>
<p></code></p>
<p>echo var_dump($user);</p>
<p>在这个文件中，首先得到json_encode.html文件中POST表单域txt_json的值，放入变量$json_string中，而后判断，如果当前PHP的设定为magic_quotes_gpc=On，即传入的双引号等会被转义，这样json_decode函数无法解析，因此我们要将其反转义化。而后，使用json_decode函数将JSON文本转换为对象，保存在$user变量中，最终用echo<br />
var_dump($user);，将该对象dump输出出来，最终结果是：</p>
<div><code><br />
object(stdClass)#1 (3) {</code></div>
<div><code>["name"]=&gt;</code></div>
<p><code>string(10) "hanguofeng"</p>
<p>["email"]=&gt;</p>
<p>string(18) "example@domain.com"</p>
<p>["password"]=&gt;</p>
<p>string(10) "hanguofeng"</p>
<p>}</p>
<p> </p>
<p> </p>
<p></code></p>
<h2>json_encode函数实例</h2>
<p>在这个例子中，仍然是由两部分构成的，即json_enode.html和json_encode.php。在json_decode.html文件中，基本与json_decode.html文件的表单类似，但是不同的是，这次我们要从json_encode.php文件中获得相应用户的JSON文本，先来看这个PHP文件吧：</p>
<div><code><br />
Class user</code></div>
<div><code>{</code></div>
<p><code>public $name="";</p>
<p>public $email="";</p>
<p>public $password="";</p>
<p>};</p>
<p>$myUser = new user;</p>
<p>$myUser-&gt;name="hanguofeng";</p>
<p>$myUser-&gt;email="example@domain.com";</p>
<p>$myUser-&gt;password="hanguofeng";</p>
<p>$json_string = json_encode($myUser);</p>
<p> </p>
<p></code></p>
<p>var user = echo($json_string);</p>
<p>这个文件首先建立类user，而后获得一个user类的实例myUser，并设定其用户名、邮箱和密码，接下来使用json_encode函数将其转换为JSON文本，保存在变量$json_string中，最后输出一段JavaScript代码，以在JavaScript中建立全局变量user。</p>
<p>接下，我们需要在json_encode.html文件中引入json_encode.php文件，并得到user对象的各个属性，在这个文件中，你需要注意两点，第一是，我们以这样的代码引入json_encode.php文件为JavaScript文件：</p>
<div><code><br />
&lt;script src="json_encode.php" type="text/javascript"&gt;&lt;/script&gt;</code></div>
<div><code> </code></div>
<p><code> </p>
<p></code></p>
<p>第二点则是：</p>
<p>我们在文本框代码后面加入JavaScript的代码，对文本框的value属性进行操作，分别设定其值为user对象的相应值。</p>
<h1>实践出真知</h1>
<h2>背景说明</h2>
<p>OK，各位亲爱的朋友，在经过上面这么多这么多的零散的关于PHP的串行化和JavaScript的串行化—JSON的说明后，我们来做一个完整的东西，在这里面，我们涉及了JavaScript中的对象操作、对象串行化，还涉及了当串行化的JSON文本传输到后台的PHP时，PHP进行的相应处理。<br />
这里需要说明的是，为了将内容聚焦于本文所阐述的领域，我们将这个项目精简了很多，在这里讲的并不完全是实际生产环境下的做法，而是为了突出串行化的应用，在具体的地方我会详细说明，希望不影响你对整体的理解。<br />
我们要完成的小案例是一个在线记事本的程序，用户可以在前台添加若干个Tab（即通常所说的选项卡），每个Tab保存一定的文本内容，你也可以将它当作一个动态的选项卡生成和管理的程序。<br />
程序的运行界面如下图：</p>
<p><img src="http://i.namipan.com/files/38220519b5b390b0467dd40e10792f55f3c9979f662100008b3a/0/PIC01.gif" alt="图1" width="553" height="151" /></p>
<p>在这里，你可以看到有若干个Tab，当点击这些Tab时，下面将显示Tab的内容，同时你可以删除Tab和新增Tab，在完成对Tab的编辑后，可以点击“保存”按钮，将改动传输到后台的PHP进行处理，并保存在服务器上。</p>
<h2>前台JavaScript部分</h2>
<p>在前台的notepat.html文件中，我们要使用JavaScript完成大多数对Tab进行管理的任务，因此我构建了一个Tab管理的类，用来对其进行添加、删除等操作，这个类如下所示：</p>
<p><img src="http://i.namipan.com/files/c133ba96caeb42302294e67e18c08118707b0dc35e180000dcad/0/PIC02.gif" alt="图2" width="397" height="232" /></p>
<p>tabManager类的各个属性、方法含义如下：<br />
_tabs：“私有属性”（加引号的原因是JavaScript中并没有私有公有的概念，这里只是从设计上来讲），该属性中存储了当前的tab数组，任何对Tab的操作将最终存储在这里。<br />
_lastIndex：“私有属性”，表明最后添加的索引，用于对各个Tab进行唯一标识。</p>
<p>getTabs()：返回当前的tab数组。<br />
setTabs(tabs)：设定当前的tab数组。<br />
add(ptitle,pcontent)：新增一个标题为ptitle，内容为pcontent的tab。<br />
del(pid)：删除id为pid的tab。<br />
clean()：“私有方法”，用于删除某个tab后，对tab数组进行精简压缩。<br />
getTab(pid)：用于获得指定的单个tab，参数pid为要获得的tab的id。<br />
debug()：预留的debug方法。</p>
<p>同时注意我们的tab对象有三个属性，分别为id、name和content。<br />
这样，基础类的架构我们就讲解完毕了，这里由于其详细代码与本文话题关联不大，就不再详细列出和讲解了，稍后可能会单独发表文章来说这里。<br />
那么，我们还需要构建一些函数，作为控制器，来沟通页面上各个按钮的点击事件和之前建立的tabManager类，这些函数包括：<br />
selTab(o)：当点击页面某个Tab时，切换内容区域以显示相应Tab的内容，传入参数为所点击的连接对象。<br />
newTab()：当点击“新建Tab”按钮时，负责询问用户新增Tab的信息，并调用tabManager.add()方法将用户输入的Tab信息建立一个新的Tab对象。<br />
delTab()：删除当前激活的Tab。<br />
saveTab()：将对Tab的所有更改提交到PHP中。<br />
loadTab()：加载Tab。<br />
showTabContent(id)：被selTab()函数调用以显示指定id的Tab的内容到内容区域。<br />
draw(tabs)：根据传入的tabs数组重绘Tab导航区域。</p>
<p>那么，这里我要重点强调的函数就有两个，分别是saveTab()和loadTab()。<br />
先来看saveTab()函数：此函数源代码如下：<br />
function saveTab()<br />
{<br />
document.getElementById(&#8220;json_string&#8221;).value = JSON.stringify(tabManager.getTabs());<br />
document.getElementById(&#8220;frmMain&#8221;).submit();<br />
}<br />
呵呵，好像比较简单啊，这个函数首先通过调用tabManager类的getTabs()方法，获得我们所操作的Tabs数组，而后调用json2.js文件中的JSON.stringfy()方法将其串行化，得到串行化的JSON文本后，将其赋给隐藏域json_string，并提交表单，这里我采取了简单的方法，其实你在这里也可以采用Ajax的方式，将JSON文本传递到PHP中。<br />
另外则是函数loadTab()，其代码如下：<br />
function loadTab()<br />
{<br />
tabManager.setTabs(notes);<br />
draw(tabManager.getTabs());<br />
}<br />
这里需要说明的是，我们在本文件的开头，通过如下代码：<br />
&lt;script type=&#8221;text/javascript&#8221; src=&#8221;load.php&#8221;&gt;&lt;/script&gt;<br />
引入了一个经过后台处理的（你可以看到，扩展名为PHP）JavaScript文件load.php，。在这个文件中，建立了一个tab对象的数组notes。因此，在loadTab函数中，我们调用了tabManager类的setTabs方法，设定tabManager类的“私有属性”_tabs的值为notes数组，此时就完成了对Tab的加载。</p>
<h2>后台PHP部分</h2>
<p>当用户在网页上点击“保存”按钮后，会触发前面所讲解的saveTab()函数，最终提交表单到save.php页面，该页面读取用户提交的JSON文本，并将其转换为PHP对象，进行后续处理，其代码如下：<br />
<code><br />
$json_string = $_POST["json_string"];<br />
if(ini_get("magic_quotes_gpc")=="1")<br />
{<br />
$json_string=stripslashes($json_string);<br />
}<br />
$notes = json_decode($json_string);<br />
foreach ($notes as $note)<br />
{<br />
echo $note-&gt;title."&lt;br&gt;".$note-&gt;content."&lt;br&gt;-------------------------&lt;br&gt;";<br />
}<br />
$p = f open("load.php","w+");<br />
f write($p,"var notes=".json_encode($notes).";");<br />
f close($p);<br />
</code><br />
首先通过访问全局集合$_POST来获得提交的json_string隐藏域的值，而后进行处理，如果PHP的配置magic_quotes_gpc为On，则此时提交的文本中，引号会被转义，如果不进行处理，那么后面的json解码操作会失败，因此我们调用函数stripslashes()将其反转义。<br />
接下来我们使用json_decode()函数对提交的JSON文本进行解码，返回的对象保存在$notes变量中，此时$notes变量为一个数组，数组中每一个元素即一个Tab对象，为了清楚的看到这一点，我们对$notes数组进行迭代，依次打印出数组中每一个Tab对象的标题和内容，最后，我们打开文件load.php，将使用json_encode进行JSON编码后的$notes对象写入此文件，以待notepad.html文件调用，这样就完成了对对象的持久化存储工作。<br />
这里仍然需要说明的是我们精简的部分：在实际的生产环境中，你很可能需要在迭代$notes数组时将每一个Tab对象的信息写入数据库中，以方便其他的部分调用，而在load.php文件中，你可能并不是直接将JSON文本写入此文件，而是从数据库中读取一个结果集，而后迭代结果集，来生成一个PHP的数组，并将PHP数组进行JSON编码后，输出。<br />
好了，絮絮叨叨一大堆，简单点用个图来表示吧：</p>
<p><img src="http://i.namipan.com/files/84e97995562c3988d17d434980def68a9fecf13788100000a104/0/PIC03.gif" alt="图3" width="512" height="274" /></p>
<p><img src="http://i.namipan.com/files/f7030628503797b9fd1d40f72d33b0536def4026bb120000edb9/0/PIC04.gif" alt="图4" width="512" height="274" /></p>
<h1>我还有话要说</h1>
<p>各位亲爱的~读者朋友，我们这篇“长”达一万五千字的连载完成了，在本文中，我想你了解了关于对象串行化的一些基本概念以及串行化在PHP和JavaScript中的使用方法。<br />
串行化只是一种思路，他的妙用在于你熟悉了在各类语言中对对象的操作之后，JSON和XML各有特点，根据自己的情况进行优选才是王道。<br />
欢迎大家在论坛或者博客中与我交流。</p>
<h3  class="related_post_title">相关内容</h3><ul class="related_post"><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-3" title="听小韩聊PHP项目开发(3)–切分你的系统">听小韩聊PHP项目开发(3)–切分你的系统</a></li><li><a href="http://www.hanguofeng.cn/archives/web-server/php-project-development-2" title="听小韩聊PHP项目开发(2)&#8211;观察你的项目">听小韩聊PHP项目开发(2)&#8211;观察你的项目</a></li><li><a href="http://www.hanguofeng.cn/archives/security/configure-fast-in-lamp-on-windows-with-xampp" title="Windows下AMP平台配置FastCGI方法（以xampp为基础）">Windows下AMP平台配置FastCGI方法（以xampp为基础）</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.hanguofeng.cn/archives/web-server/php-serialize-json/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->