也许您会觉得代码并没有什么区别(甚至看起来采用函数模块的代码由于不需要取得新的对象而显得更简洁一些),而真正的不同是发生在include的文件里面。采用函数模块的方法将相关的函数集合在一个文件中加以组织(有些系统还不能做到这一点,那么就会造成异常混乱的局面),而采用类封装的方法在每一个文件中声明一个和文件名相同的类(比如在Member.inc.php声明一个Member的类,这一点和Java的规定相似);而在使用时,都需要先进行include(如果采用函数模块又没有进行很好的组织,也许有些人就会很"简便"的将所有函数include进每一个页面--PHP可不是Java那样编译执行,光是解析这些函数就会花费一段时间),但是关键就在于采用类封装的方法可以清楚的指明调用的位置--某个类(Member)的某个方法(login):从避免名字冲突的角度来说这一点是非常成功的;而对于代码检查和维护而言,方便程度更是不言而喻。设想一个页面需要完成若干功能,因而需要include数个文件:采用函数模块的方法不能够轻易的从函数调用中找到函数本身所在的文件(如果函数名称或者include文件名称没有什么统一规则,那么这个工作就非常艰巨了),而采用类封装的办法可以根据类名称和类文件名称准确定位类方法代码的位置。(也许您会认为这样一个小小的好处不足挂齿,但是经历一个维护工程之后也许就不会再有什么异议。)
以上是采用类封装方法的原因,决定采用这种方法设计系统只是第一步;完成整个系统的设计还有很多可以借鉴的经验。
- 部分设计可以借鉴面向对象的思路。虽然PHP中没有接口和抽象类的定义,继承机制也非常不完全,但至少具备了基本的类定义和简单的继承关系。类似"公司-雇员"、"卖家-商品-买家"这类显而易见的关系可以很容易在系统中通过类和类关系定义。既然PHP可以做到这一点,就按照实际的逻辑关系去定义即可。
- 经常会在系统中出现的另一个情况是关于个体和列表的关系--这样说也许难以理解,想象一个BBS系统中的帖子列表和每个帖子之间,就是这样的关系。根据设计经验,这样的关系大量存在于PHP或者其他Web系统中。对于这类关系,我个人建议可以采用以下Item和Item_List的类封装方式:
- 由于PHP对于类的成员变量和方法并没有语法上的访问限制(均为公开),因此会带来对象使用方面的某些混乱。基于此,建议在开发团队的代码规范中加以规定,从代码应用的级别上控制这一情况:
首先,可以通过对成员变量和方法的注释来说明其属性,由此使用该对象的其他开发人员可以了解自己的使用方法是否触犯了规定的访问限制。(如果采用phpdoc等自动文档生成的工具,开发人员甚至可以在不翻阅类源码的情况下通过浏览类文档正确使用它。)
其次,对于成员变量访问限制的考虑,可以将一些主要的、经常需要被访问或更改的变量(在注释中)声明为公开。这样的作法可以省却大量get()和set()方法的代码--虽然在其他的面向对象语言中这一点被认为非常丑陋,但是记住PHP不是Java,只要这样的用法合理,就应该大胆使用。 - 从上面的示例代码中您也许已经注意到了注释的比重--虽然大家都了解注释的重要性,但是仍然有必要提出。这个示例中采用了Javadoc的样式,利用现有工具也可以很容易的直接生成文档(当然您和您的开发团队也可以定义自己的合适注释样式和文档生成工具)。对于系统分析员来说,您在设计阶段完成之后交付给您的开发伙伴的代码部分很可能就是这些注释占绝大部分的框架代码;你们之间交流的工具除了那些没完没了的图表之外就是这些程序员最熟悉的代码和注释了。
在PHP系统中进行类的设计虽然不像构建面向对象系统那样需要各种合理的模式介入(也没有这样的"本钱"为之),但还是需要一番思量的。逻辑上的合理性和操作上的可行性都是检验的标准。
(说到类设计,又想到了适合PHP开发的IDE问题。据我所知比较专业一些有Zend出品的Zend IDE;另外还有作为JBuilder的Open Tools出现的借助JBuilder的PHP开发工具;不过最常用的还是PHPEd或者UltraEdit之类的编辑器。如果现有的编辑器可以非常聪明的支持PHP的类设计和代码实现就非常理想了。)
关于View
最后说到的是View方面,虽然这部分内容与网页设计人员联系比较紧密,不过PHP项目(以及其他Web项目)的系统分析员也必须关注这一话题。可以看出MVC模式的应用使得网页开发人员和程序设计人员的各自工作成果不会像以前那样互相影响,自然可以提高各自的工作效率(相互关系也许会比以前更加融洽一些)。但是对于系统分析员来说,将用户界面分离为各个独立的网页模板需要进行许多分析工作。
首先是确定整个系统的流程,这一点在系统设计的初期就应该做到。而对于View视图/界面和Controller控制/流程来说,所有需要的页面都是围绕此流程产生。不过通常此时能够在流程图上看到的也许只是相关的参数在各个页面之间传递,却不能了解各个页面展示的内容--这就是下一步分析用户界面需要进行的工作。
在分析用户界面的工作中,第一步可以确定各个页面核心、对于完成流程必不可少的用户界面元素(表单和表单域、链接等);第二步是确定页面中需要出现的导航内容;最后还需要依据流程复核。还是以上文的用户登录为例。对于/member/login.php这个关键的页面,第一步可以确定的是在用户提交之前应该显示一个表单,表单包含两个文本框供用户输入用户名称和密码;而提交之后根据流程在本页面中不需要有用户界面,取而代之的是利用Controller控制/流程这一逻辑层进行重定向。而第二步需要制定该页面中(准确说是在显示登录表单时)需要提供的导航链接,在这里可以加上到系统的主页或者其他非注册用户页的起点的链接(方便用户临时决定取消登录)以及一个注销现有用户的链接(针对已登录用户)。之后进行复核,此时也许会发现这一设计似乎没有考虑到在登录前更好的区别是管理员登录还是普通用户登录,那么就可以在表单中增加一个隐藏域表示选择登录的用户是准备以管理员还是普通用户的身份进行登录。
确定完用户界面的元素,并不意味着可以将这些分析结果交付网页设计人员进行制作了;还有最关键的一步没有实施--为分析完成的各个页面制定模板所需的变量名称。对于以上的用户登录实例,如果系统有识别曾经登录用户的功能(依据之前访问时在客户端设置的相关cookie值)并且把这个用户名称显示在登录表单的用户名称一栏,此时就需要在member_login.dwt设计中说明该表单域将被赋值为一个模板变量(比如{USERNAME})。这一步骤完成之后就可以交付网页设计人员进行制作了。
需要指出的是,在编码阶段很可能局部的一些系统设计需要进行修改,这其中也许就包括对网页模板的修改,需要仔细处理。
对于代码组织的补充说明
还有几个文件和目录没有在上文提及:
- config.inc.php -- 如果您熟悉phpMyAdmin或者其他phpWizard.net释出的项目,就应该非常清楚这个文件的作用:定义本项目范围内的全局变量(在每个页面中被include)。我个人认为这是一个非常良好的设计,因此也提倡在项目中应用。另外,为了保证与项目中其他的变量冲突,建议在该文件中定义一个多重数组,而各种全局变量都以该数组的某一个值出现。这样方便团队中的其他开发者只需要避免一个变量名的使用,而不是避免所有config.inc.php中出现的变量名。使用这个文件的另一个好处是由于将关键的变量(比如与服务器环境相关的变量)集中定义,可以方便的安装和移植整个项目。
- security.inc.php -- 顾名思义这个文件控制并实施整个系统的安全策略。关于安全问题,可以想到的是两种控制方案:在每个控制流程页面顶端针对本页面加以控制以及采用一个控制文件整个控制并被加入每个控制流程页面。我个人提倡采用后一种方式,原因也很简单:定义简单而且维护方便。虽然相比每个页面单独定义,也许会损失一点点效率(一些不需要安全控制的页面也需要include该文件并进行判别),但是获得的是对系统安全的整体控制以及代码维护的便利(损失一个if…else…的判别换取这样的结果还是很值得的)。
- /Temp -- 很明显存在于这个目录下的都是一个临时文件,并且这个目录其实并不会出现在项目正式发行的版本中。如果开发时对一些函数的使用不甚明了或者试验一段没有相关经验的代码,都可以在此目录下建立文件;因为该目录就位于项目代码之中,可以非常便利的取得项目运行的上下文环境,大大降低了试验代码的成本。
- /admin -- 通常对系统的后台管理内容应该放置在一个独立的目录中,我个人比较喜欢admin这个简写词(当然也有一些情况系统分析员认为不应该设置一个容易猜测的管理目录名称以增加一重对系统安全的保护)。
- /css和/scripts -- 都是与网页设计也就是View视图/界面有关的文件存放处,分别是样式单和客户端脚本。这样做的好处在任何一本讲述网站规划的书籍中都会有所提及。
[
本帖最后由 kakashilw 于 2008-3-10 20:56 编辑 ]