与PHP开发有关的模板问题

关于PHP的模板的确是一个说起来容易做起来麻烦的事情。随便一数大概有20种以上的选择,光pear里面就包含了5中不同的模板,实在让人头疼。 千万不要人云亦云的说这个好那个不好,选择模板之前最好先应该搞清楚模板的真正目的是什么? 简单地说,模板的核心目的就是一个 team work。主要的作用方式有两种: 1、分离HTML和PHP使网页设计师和PHP程序员合作更加愉快。 2、分离显示逻辑和事物逻辑,使得核心事务逻辑的变更和应用程序的扩展更加容易和灵活,也就是说使得程序员之间合作更加愉快。(这一点经常被人们忽视或者误解,总以为把PHP从HTML中弄出去就叫分离显示逻辑和事物逻辑了,如果这样当初又何苦让PHP和html 混在一起呢?) 搞清楚这个模板的真正目的是什么,就容易做出正确的选择了。 如果只有你一个php程序员但是需要和其他的网页设计人员一起协同工作,那么选择能够分离HTML和PHP的模板就可以了,phplib (现在好像集成到 Pear 里面了 http://pear.php.net/package/HTML_Template_PHPLIB)或者 FastTemplate 都是这样的东西,很简单容易上手。 如果你的网站界面比较丑陋并且主要由程序员来完成,但是功能比较复杂更需要强大的扩展功能,需要分离各个层次包括显示逻辑,那么不要用什么特别的东西,PHP本身就是最好的模板了。要注意的是在这种情况下,你要非常认真的设计你的程序,始终记住要分离的不是PHP和 html 而是事务逻辑 (business logic )和显示逻辑(presentation logic)。这也是为什么我一直对于Smarty 这种东西非常的抵触, 因为这个 Smarty 的语法太复杂了太强大了, 几乎重新发明了一种脚本语言东西, (即使是PHP的程序员也要重新学习它)。更让人费解的是 这种脚本 越是强大,越容易让人将事务逻辑(business logic )和显示逻辑(presentation logic)混在一起, 破坏了模板的初衷。 如果你既想HTML和PHP分离,得到更好的视觉设计,又想整个系统有非常强大的扩展能力能够适应html,xml,wml各种界面,而且不用去学习复杂的语法的同时提供较高的运行效率,那么这就是一个相当有挑战性的问题了。坏消息是目前还没有一个成熟的模板真正能够达到这样的要求,好消息是完成这样的一个模板并不是很难,如果你尝试过Zope或者是ColdFusion就会发现这种模板的影子, (wact http://wact.sourceforge.net/ 和 phptal http://phptal.sourceforge.net/ 就是在向这个方向发展,应该很有前途)。 模板和数据的结合(模板的调用)方式主要有两种:推的方式和拉的方式。 推的方式是用PHP将数据推给模板,就是说需要程序员明确地为模板中的每一个变量赋值,将他们绑起来。 而拉的方式则像把php 和 html 混在一起一样,模板种的变量主动把数据拽进来。 说到模板就不能不提到另外两种东西: phphtmllib 和 quickform(http://pear.php.net/package/HTML_QuickForm) 这两种东西是用传统的方式来通过各种页面构件来完成HTML的页面的 整个页面的构造完全掌握再程序员手里,也许很多编写过传统GUI桌面程序的程序员更喜欢这种方式。 更加漂亮的方案 如果做商业软件的话,Flash应该是更漂亮的方案(别搞错了,别以为就你知道php支持ming 和swf库可以动态生成 Flash,我说的不是这个。) 我要说的是支持Flash Remoting 的方案,这种东西才是真正有意义的PHP和flash的结合。由视觉设计师完成flash部分,PHP 程序员通过 flash remoting 的方式将 数据发送到 flash 做成的客户端中。 目前有两种方案: AMFPHP http://www.amfphp.org/ 由于Macromedia Flash Remoting 传输数据时 使用的是一种特有的更加高效数据格式, 所以AMFPHP通过分析数据格式,在服务器端构造了相应的php类来接收,解析和编码这些数据从而达到交换信息的功能(就像Samba一样,应该属于一种 Hacking 吧)。 PHPObject http://ghostwire.com/resources/phpobject/ PHPObject 则采用了另外一种方法,通过在flash中嵌入一些actionscript的组件通过开放的格式soap来传送数据。 其实关于PHP的模板还牵扯到很多其它的问题,一时半会我也只能写这么多了,有时间了我会写到书里的。 你的想法呢? 同意二楼的。我一般不用什么所谓的HTML模板,而多用二楼说的那种事务逻辑与表示逻辑分开。就是说,显示逻辑用单独的单元,事务逻辑则用OO来封装,有些类似于JAVA的SERVLET和JAVABEAN进行二层分离。同时,为了能与网页设计人员配合,即同时又做到代码与HTML分离,我采用二次编译模板的办法。即在最初的元素为资源文件与框架文件,然后将这两种文件进行第一次编译,组合成不含代码的模板文件,由网页设计人员对这个模板文件进行修改,这个文件中含有少量特殊语法标记,但不复杂,主要是些变量与格式及少量及必要的流程控制。设计人员完成之后,对模板进行第二次编译,生成显示逻辑的PHP脚本,就是说将模板编译成直接可用的PHP脚本,而且只涉及显示。事务逻辑在显示逻辑之前运行,一般只调用类的实例即可,显示逻辑中的变量都可以与事务逻辑相关联,其实这里就用到了二楼说的拉的方式,也就是在显示逻辑中,代码与HTML是混在一起的,但主要功能是显示界面,而事务处理,如从数据库中取数据等都在事务层处理了。只是这个最后的显示逻辑一般不用自己写PHP脚本,而可以直接从模板中编译出来。用这种拉数据的方式比用推的方式效率要高,因为对 PHP解释器来说,它无须两次解析(其中一次是用脚本解析模板)。用这种预编译的方式一般来说只须生成一次显示逻辑即可,以后就直接用了,无需每次都要象 PEAR中的那些模板在运行时人为解析。用二次编译的方法还可以做到高度易扩展性,资源文件中只有纯常量,结构文件中只有纯结构,资源文件中的常量可以改成各种语言,结构文件可以不变,两者经过第一次编译与合成生成真正的模板文件,它不含任何PHP语法,只有一些放在 之间的结构标记与混合了资源文件中字符串的HTML页面,这时可以供网页设计人员进行随意修改,修改完后,经过第二次编译,直接生成表示层的PHP脚本,这时该脚本就是PHP代码与HTML代码混合的。 我对模板进行了规划,而且写了这么几个类:ResourceLoader, BlockPrecompiler, BlockCombiner, TemplateCompiler 第一次编译前的结构文件叫block,各个block可以单独编译,也可以一起编译,编译完了按main block的结构将被包含的block 组合进来生成一个模板文件——这个文件就是供网页设计人员修改的文件,当然也可以修改第一次编译后的各个小block,然后再组合。大致的流程是: 1、先用ResourceLoader从指定的语言包资源文件中调入资源,并解析,生成一个数组放在这个类中; 2、用BlockPrecompiler预编译指定的block,既可手工单独编译,也可根据主入口block的文件包含情况自动地批量编译,对已存在的编译过的block可以选择覆盖或是保留(手动,类方法不会根据文件时间自动判断是否覆盖,因为考虑到网页设计人员可能会自己修改编译后的 block); 3、用BlockCombiner根据主block入口文件中的信息将已编译的block进行包含组合,生成一个模板文件,以供网页设计人员修改。该类只进行组合,不编译,除非发现被包含的文件尚未被编译,但主入口block必须被预编译,否则将会错误退出。总之就是保证这些block至少被编译一次,如果要求覆盖则强制再编译。生成的模板文件不含PHP代码; 4、网页设计人员修改经过一次编译的模板文件; 5、用TemplateCompiler对网页设计人员修改过的模板文件进行第二次编译,生成对应显示逻辑的PHP脚本文件,以供程序使用。 这么做主要是考虑到模板修改不是那么频繁,而使用模板却很频繁,因此最好的办法是直接用PHP与HTML混合这个固有的优势,而不是机械地强调代码与HTML完全分开(完全分开其实是极为愚蠢的想法)。之所以要分开主要是为了网页设计人员的方便与透明而不完全是为了程序本身——程序本身只要做到两个逻辑层分开就足够了,通过模板的二次编译基本上比较好地解决了这个矛盾,而且同时也实现了事务逻辑与显示逻辑分开。由于模板语法设计并不复杂,设计时也尽量做到简单与严格,因此这几个类的源程序也不大,仅18.2K,加上一些辅助的函数,总共不超过22K,主要也还是利用了强大的正则表达式。而且它们一般在写WEB应用程序时是用不到的,主要是在写模板编译环境的程序时才会用到,因为在WEB程序中要用模板时,只需要简单地include一下第二次编译后的文件就可以了。 至于说用FLASH+PHP,这个我也干过,用标准XML的方法可以做任何事,后台的PHP可以不必有任何显示性输出,它输出的是标准的XML数据,主要是前台的FLASH将返回的结果显示出来。不过说实话,这个玩意限制比较大,比如说UNICODE就是一个问题,虽说FLASH6以上对 UNICODE支持好多了,但它目前还是支持得不够,至少三个字节的UNICODE它就支持得不好,而且有时还不太方便。其实说穿了,这个FLASH+ PHP其实就是在SERVER与CLIENT端之间传递XML格式的数据,后台处理用服务器端的PHP,前台显示用客户端的FLASH,与最老的C/S的应用程序从实质上来说没有什么区别,唯一的区别是传递数据用的高层协议不同,这时PHP本身就是服务器。 那是没有问题的,不过现在还不行。因为我现在做的是一个框架,这个模板编译单元只是整个框架的一个模块,单独拿出来可能不能运行,而且我的例子与WEB程序也是建立在我这个框架上。这个框架就是我说的用了DELPHI工程的架构,库与程序单元是分开的,目录搬移是没有任何问题的,一些纯静态的媒体文件如图片等还可以放在另一台不支持PHP的主机上。 到目前为止,共做了大概上十个模块,计有: 1、打包压缩(TAR及TGZ,直接封装各种功能,计添加文件,删除文件,解包,列表,更新,添加更新等,全部支持批量操作,并支持通配符,支持子目录递归压缩,文件名大小写敏感可自定)已完成 2、编码转换(GB18030,GBK,GB2312、BIG5、UTF8,16,32互转,中文繁简互转,中文字符串及子串精确长度等;有扩展规范,可方便地扩展到日文,韩文等,内部编码用UCS4。以上转换除中文繁简互转可能有偏差外,其它都是精确转换)已完成 3、时间处理(精确处理世界各时区——时区精确到十五分钟,WIN2K区域设置中的时区全有,对同一个时区但不同的地方有不同的处理方式;精确全面地处理世界各地夏令时——计算误差一般不会超过2秒,所有夏令时的起止点全部参考WIN2K的时区设置,例如加拿大东部时间从每年四月的第一个星期日凌晨二点开始夏令时到每年十月的倒数第一个星期日的凌晨二点为止等等,不过夏令时信息尚未输入,太多了,只是做好了接口;还有计算生肖、星座等——生肖精确到农历新年,星座精确到天;所有与时间有关的计算用UNIX时间戳,输出为转换后的时间戳;有关生肖与星座的计算输出用整数,因此无本地化的问题) (上星期更新:改写了时间日期模块的部分内容,使时间戳支持从公元元年到9999年,弥补了UNIX时间戳的不足,并增加了1582年的日期修正,闰年判断也相应调整,星期几的计算也相应地针对1582年的修正加以调整,能计算某年某月某日与公元元年一月一日的距离,起点以每日00:00:00 开始计算,绝对精确。同时兼容UNIX时间戳,就是说在1970到2038年之间的时间戳与扩展后的时间戳一致。时区计算也采用新的函数,但接口不变。新增计算符合ISO8601规范的日期)已完成 4、权限系统(二维权限,可定义用户及用户组,支持允许与拒绝权限,可定义预设组权限,可定制某个具体空间的策略,可动态设定某用户在某空间是否在预设组——重载几个方法即可,用一个方法调用即可知道某用户在某空间的具体权限;所有的参数全部为字符串输入,方便存贮在数据库中)已完成 5、分页(这个不用多说了吧,支持上页、下页、首页、尾页、上几页、下几页,支持直接跳转到第几页;每页显示记录数准确;可容错,如果输入参数错误可自动更正)已完成 6、文件锁(两种锁方式——系统锁及模拟锁,可人为指定方式,但不支持自动检测,因为那不是这个类应该做的事;支持文件锁定——包括共享锁定和排他锁定;除了文件锁定外还支持页面锁定——只锁定一个文件的部分页面,不过只支持写锁定,读数据不能锁定,这种页面锁定也可改成单条记录锁定,原理差不多)已完成 7、通用数据库接口(简单的,目前只支持MYSQL,可扩展,可支持限制查询LIMIT——接口通用,只需重载几个方法即可,但功能不复杂,也不是最完善的,写完善的太多了,对我来说也没有必要)这一部分已完成了 8、二次可编译模板(支持资源文件、语言包、定制的流程控制,模板与代码完全分离;资源文件用自定义的格式,清楚明了,尤其便于翻译,无需在整个 HTML文件中找零散的文字进行翻译,而只需对资源文件中的条目一一对应翻译即可,而这些条目支持是支持格式输出的;语言包还支持单复数的不同——类似于 JAVA中的本地化;二次编译模式,第一次从一组资源文件、语言包和流程控制文件编译成模板文件,该模板文件可供美工自行修改,不含程序代码;美工完成后,再由程序进行第二次编译,生成可发布的PHP脚本文件,当然也可以在使用时动态编译)已完成 9、缓存(尚未开始,还需重新构思)过一阵子再写它 10、标签系统(尚待完善,原来写过一个,思路不错,但效率偏低,现准备重新设计流程;原理:将字符串编译成中间代码存贮,可正转也可逆转,存在数据库中的是中间代码,需要编辑的时候就逆转,需要显示的时候就正转,逆转比较快,只要去掉相应的标记即可,正转时由于需要转的是中间代码,不用再分析,而是直接替换即可。只有在往数据库里写的时候才需要把最原始的明文转编译成中间代码,这个需要一点时间和资源,但因为一般写的机会比较少,因此还是值得的。此标签系统特点是:标签严格,安全性好,不会出现什么破坏现象,也不会有什么漏洞;标签可任意交叉重叠而不会导致页面被破坏,因为我在编译时用了堆栈来判断,凡是不能匹配的全都不算合法标签,而不是仅仅只用正则替换;扩展性好,只需重载某些函数即可)这个太复杂了,上次断断续续写了一两个月,这一次看来时间也不会太短。 还有其它一些模块,包括自己写的与修改别人的,大部分用OO写成。还有一些库函数等等。 对了,所有的这些模块,与界面都没有任何关系,全是类与函数,只处理事务,不显示输出具体内容,要具体显示,可用继承的方法来实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值