分页: 2/2 第一页 上页 1 2 最后页 [ 显示模式: 摘要 | 列表 ]
在公司项目中实验了一把PHP下的MVC,在我看了不多的几个MVC框架,我个人对其封装不算满意,zend的没看过看过介绍,但其层次和组织结构过于复杂而且其重点也是在于通过zend框架使得功能更方便。倒是国内的两大主力fleaphp和thinkphp,flea我曾经简单用过,感觉各方面都还不错,重量也把握不错,thinkphp对内核的东西改变较多,而且有些思路也相当不错。think的代码我基本上都读了(0.92)现在好像有1.0了,没有再仔细读,但基本思路已经了解了。于是非常冲动,也想实验一把,曾经也为了体验一把MVC设计,基于spring的mvc框架做了较大规模的封装(不过事后发现是我对spring了解不够足,其实我做的封装spring也基本都做了,包括所谓的command概念我居然也实现了一个类似的玩意)。这次手痒于是我们就开始吧。但在实践中遇到了相当大的阻力,首先是进度根本无法保证,导致最后被罚了1k工资,但我并不太在乎这点,因为从这里边积累大量宝贵经验,当然也让我对PHP彻底失去了兴趣,不过这是后话,首先来看看我的MVC概念。

个人的MVC思路均来自于《J2EE设计模式(J2EE Design Patterns)》一书,最基础的框架:


这是一个标准的单分法器模型,但我会作几点说明:
1 RequestObjected,这个是所有用PHP的程序员可能不理解的地方,事实上PHP是一种为网站所生的语言,JAVA这方面没有任何的天生优势,JSP更感觉是一个可笑的玩具,现在大多数做企业应用还在用传统的JSP技术是会被BS的,BS的地方我在这里不做讨论了。回来吧,首先我们知道PHP对于Request有非常理想的封装了,包括如下的全局对象,$_GET $_POST $_COOKIES $_REQUEST $_SESSION 但请大家注意,这些对象都是全局变量,对于封装来说这是完全违反对象法则的,所以我对$_GET 等等做了封装在我的类里边会在BaseAction中有一个叫ParamData用作request对象 cookieData对应cookies sessionData对应session,为什么这么做,对于一般人的理解这样等于增加了消耗,那你就错了,我绝不单单为了对象而作生搬硬套,这样做的好处有如下:
1) 完成request层的编码转换,比如开发UTF-8的前台是,目前所有的框架都使用了,不同的文件编码模式,这个方法在我看来非常愚蠢,可以看到fleaphp就有utf-8和gbk两种编码的源码,这种方法对于开发来说不是什么好事情,而我在这里做了封装就可以在基类做自动化转换,已知我的程序都是gbk编码,那么你用什么编码在配置文件中有,可以实现对request的自动编码转换,再也没有编码困扰了。
2) 使得这些只读对象成为了可读写的对象,很多人会问这是干什么?当然有用!因为你别忘记了过滤器,这些过滤器本身也是一个缩小版的action如果得不到它的“爸爸”怎么干活?但这些过滤器都是没有返回的(我设计成没有返回的,因为PHP的对象太差)但这样就有问题了,我做了一个操作怎么告诉爸爸呢?比如我做一个验证工作,过滤了某些request的危险字符,怎么告诉爸爸?好了我的paramData对象就是干这个的,如果你用$_GET $POST,那么你只能哭爹喊娘了!
2 模板,这边模板写得非常粗略,这也是我的一个亮点,当然我得承认这个思路来自于目前公认的最好的MVC实践ROR的思路,顺便说下我整个框架的配置非常少,这些都是ROR的约定代替配置的思路,对于JAVA习惯用SPRING的同志,我想写个几百k的配置文件很正常,更有甚者以配置长度论水平,这也是一个笑谈啦,但至少在PHP不用这样,原因就是PHP是脚本,本身PHP的任何程序都是脚本,只要你需要,完全可以这么搞。好了,说了一段废话,回到模板,ROR的思路是什么?我现在这样实现的

模板path= BasePath+actionName/MethodName.DocmentType
所以你会看到我的模板目录下文件爆多,这是一般人应用所没有的,但我至少认为这里有两个好处:
1 可以对应找到所有的文件
2 可以有效的灵活配置,和ROR的思路有点不同,我至少可以通过Action改变当前模板(ROR也可以啦,不要误解了),但后面会在Action部分说到一个创新的地方就是内存模板概念(首先说明这对于很多人是蛮新颖的,但在我们公司这已经一直这样用了,我只是拿过来改个名字封装下而已),所以这里必须要有个灵活的方法。
下面看一个典型的Action吧:
<?php
require_once(RAILS_PHP_LIB.'/class.Action.php');
class tag extends Action {

//主页方法
function index(){
$user = $this->userClass->getUserInfo($this->paramData['userid']);
$articles = m("articles.getArticleList",array("page"=>1,"user_id"=>$this->paramData['userid'],"size"=>50));
$this->addTemplateData("user",$user);
$this->addTemplateData("articles",$articles);
}


}
?>

至于代码的含义以后会介绍的,这里大家只是看看,模板的用法,大家会问模板呢?当然是在基类中实现的,至于基类怎么实现就是各自的事情,我个人觉得如果有兴趣可以重写或者继承覆盖,因为只要实现几个方法就好了。

好了,今天讲到这里,我要干活去了,忘记介绍这个东西的名字了叫:RAILS PHP,目的很清楚了,其中有不少ROR的思路,当然我对ROR的理解并不深用得也不算多,只做过两个小东西,不过我个人很喜欢ROR的思路,呵呵,今天作为引子就写到这里,下面看看我接下来会写什么:

为验证准备——UserClass接口
最核心的类——Action
Action的儿子MemoryAction
Action的流程控制,唯一没有真正对象化的地方
Action的过滤器
神奇的模板,原来Smarty可以这样玩——RTemplate
数据库层,失败的作品,但我想说说我的规划思路
分法器,异乎寻常的简单
Cache我心中的痛,PHP你为什么没有真正的Static
应用的扩展文档模型——给做CMS和BLOG等文档系统一点小思路
最后的结尾,未来的发展之路

最后说几句,对于PHP我是菜鸟,真正用PHP不过8个月的光景,只是我觉得语言是相同的其实都一样PHP虽然差,但也应该是对象语言至少可以做到,虽然这点在公司的老程序员面前得不到一点肯定,但我只想证明我的思路没问题,欢迎有人来拍砖,共同讨论才能帮助我进步,虽然个人已经非常bs php了,但是要靠它吃饭拿工资没办法,但是yy下总可以吧,那就y啦。

还要抱怨的是开发工具,我的同事们都是用editplus的我实在无法接受那样的IDE,用了zend,不过即便如此有几个问题无法解决:
1 类中应用了另外一个类,那么那个类就无法代码提示
2 对于类型无法事先确定,而我的多数函数参数都受到设计模式的影响,均是传对象的,这样就开发和调试带来了很多莫名其妙的问题,常常被参数缺失而困扰
但这些问题不能抱怨zend不能抱怨eclipse,因为PHP就是没有类型的即使所谓的class在我看来只是一个名字声明而已,这非常糟糕,看看netbeans的ruby ide如果能达到这个水平基本上无憾了可以,但现实却那么打击人,抱怨一下。
Tags: ,

万恶的无域声明

[不指定 2007/11/08 12:31 | by edwardproAdmin ]
查了整整一天的问题居然是一个极其弱智的问题。两个程序因为历史原因使用了同名不同内容的类,结果require之后造成了PHP的编译系统的死锁,表现就是访问会立即404错误,真是郁闷。。。

无类型的可怕

[不指定 2007/11/07 13:59 | by edwardproAdmin ]
不要怪我无知,我今天才知道:

$t = new Object();
$t->a = 'a';

这样都可以的。。。无法想象,对于类型居然可以这样践踏。。。这样的操作比js的prototype还要过,对类的封装是一种践踏,这样PHP所有的extends implaments都是毫无意义的,都只是一种表象而已。。。

读ThinkPHP 有感

[不指定 2007/10/03 22:11 | by edwardproAdmin ]
下午看了会程序员,看到介绍php框架,提到了thinkphp,于是下了一套来看看,它号称是一套基于rails思想的产品,那么当然着重看了下他的ROR,但是结果还是蛮失望的,首先他的ROR依然逃不了老的思路,而且在sql优化方面,他和hibernate的差距太明显了,首先是cache方面,hibernate的多级缓冲,它也写了,但是我个人认为它的代码是不知所云,完全不是那个故事,然后是把一些符号,通过内定转移的方法实现了,这不是一个好方法,而且没有必要的sql优化,当然这个要求不能太多,hibernate的优化也是基于它的hbm配置的,如果这里也有hbm我相信也能做到,但是rails不是这么考虑问题的,我个人并不喜欢hibernate的这种思路,ROR的activerecord是我认为的未来发展之路,当然它一定要解决效能问题,效能并不是完全依靠cache就能解决的,这方面要走比较长的路了,另外thinkphp对于不同数据库的支持部分可能是认为比较简单,因此并没有考量hibernate的方言机制,这意味着很多默认功能会出现问题,比如主键的设立等,这些问题已经看到它无法解决了,当然这个问题在rails里也没有解决,rails只是要求每个表都有id这个int字段,但是说实话在oracle里用int做主键会被bs的,我在oracle中都是用uuid的,主要理由就是uuid在oracle中有比自增更高超的性能,这个问题就不多说了,用过oracle的应该都知道的,在oracle里如果用自增意味着需要先select一次(当然这是oracle自己的事情,对于用户是透明的)但这样的消耗是巨大的,所以oracle里首选uuid,但在mysql中,大概90%用auto——increasment吧,否则也会被bs的,而这样的方言问题,用几个if else显然不能解决,这个问题不解决,那么thinkphp最后的数据层只能是一个死胡同。

顺便看了下它的import函数,虽然看起来像java但是问题多多,首先所谓的。×是不支持的,我看到。96里没有实现只是一个if而已,这种方法我个人认为未来都要重构,而且对于import它考虑的因素过多,反而使得他累赘,这个东西本人也写过,说实话也不太完善,主要是php的include需要绝对路径这点够傻的居然不支持相对路径,当然仔细想起来是对的,因为这是一种脚本,和java的本质就是没有编译,否则我相信完全可以产生真正的类似java的方法。但是从它目前类的函数写法如此拖沓,我可以肯定如果不改很难实现目录import因为这种只能用递归,但是他的函数本身过于累赘显然无法容易地递归,必要的分解方法是必须的,但是他没有这么做。

说了那么多不好的地方说说它的好地方,首先它实现了比较完美的单例方法,而且写了一个Base的基类,这个类类似于java的Object类。而单例的控制使用了static $statusClass并且内置了cache支持方法,而这种思路我觉得也比较可行。php的单例以前也曾经思考过,但是最后实现都很差,其实突然发现php还是很好的,因为它原始很多东西需要自己写这个时候就有个问题可以回答了,比如写一辈子java估计用static{}是天经地义的吧,谁会去思考java编译器本身怎么实现的么?不会的,除非遇到一种必须要自己去处理的语言,比如现在。正好公司有项目需要做一套简单的框架,我对mvc的理解绝不是一个控制器一个分法器那么简单,从我完全重构了spring的mvc结构开始这东西就不是我最后的目标,应该说一直以来我一直没有解决的就是model层的问题,怎么包装数据,一直以来依靠这hibernate rails结果使得自己的处理这些问题的时候就很差劲,现在终于有空间去思考了,当然任务进度我只能尽量了,没办法,否则又要被k了,上班就是这么回事情。

下面来说说我对actd的解释:
1 多表实现:多表说白了就是那么几种:1对1 1对多 多对1 双向1对多,这样分解 1对1可以理解为1对多的一种特例,多对1其实也可以理解为1对多, 双向1对多就是多对多,这是hibernate中的解释。实现上我认为直接使用rails的思路,类对象嵌套。

2 对象封装,对象表单的封装这点,但有一点做得不好,记得hibernate的update么,这是crud中一个重要方法,这个方法实现也是有一定难度的,我的想法是把得到的数据集存放在类内部,做一个更改映射表,用一个public方法比较set去修改,完后只要update下就自动执行update把修改过的变量全部处理掉。

3 DAO的兼容,这个问题是hibernate没有解决的,如果大家和我一样曾经尝试写过托管session的话就应该知道这个东西的麻烦之处了,原因就在于hibernate中没有connection的概念,而是对话概念,对话其实包含了连接,但无法拿出来用这个很复杂,而且随着hibernate的发展,它的未来可能不希望大家看到connection了,这个问题 本来上次和kavin gaven面对面的时候想问的,但是英文不行表达不好也就作罢了,但这个问题一直在我心中未决。而在php中我认为这个问题必须要解决,解决的方法很简单,开放一个dao接口,植入sql的输入和参变量的输入,但这里有个难的地方,由于php和ruby不一样不支持可变参数,这样接口很难定义,当然在java中太简单了,这也是模式书里常说的:参数传入对象吧,模式设计这样表述,当你不知道未来扩展的时候,参数传入一个复合类型总是要比传入几个固定参量要好得多。关键点,在关键时刻允许用户重写掉crud中的核心方法,代替为某个确认的dao,这个在某些时候是需要的,特别是对于设计上有问题的db系统,不可能要求对于什么都支持。

4 分页查询,这个问题对于mysql还是比较容易的,只要实现limit就好了,当然有更好的方法,我个人倾向于游标法,但这个方法貌似对于数据库的品牌有很多限制,这个以前也写过,但是实现得不够扩展,当然hibernate有方言解决了,但其他的语言就。。。所以暂时采用limit法还是可以的,至少对于mysql不要太指望,这是我个人的观点。并且要在数据层的基类中定义一个返回导航的方法。

想不明白的数据类型

[不指定 2007/09/29 19:05 | by edwardproAdmin ]


对php大概是不太了解,突然发现php的false的值居然是空不是null就是空,而true却是1,这个我实在想不明白,为什么类型松到如此程度,就像之前说过的,某些函数的返回值的类型是不确定的,这在有时候对于用惯固定类型的不是一个好事情,我往往会以为这样判断ok的情况下判断错误,原因就是不知道它的类型居然变来变去。

但php在设定时没有把false设成0也是一件很妖的事情,我是没有想明白,这样除了某些时候判断方便,大多数时候这种类型变体我觉得不容易让人融入。而且php越用越发现其类型非常松垮这是非常讨厌的事情我觉得,怎么都想不明白,不知道这样出于什么目的?

rails in php

[不指定 2007/09/15 01:39 | by edwardproAdmin ]
rails强大的地方在于约定》配置,这是一个我认为很不错的想法,特别是在java+spring配置无底洞的时候,一种更高级的模式应用我觉得应该出现了,这就是rails,推崇rails绝不是因为它开发简单,而是它带来的mvc的思路和避免配置的优越性。
经过wap项目的开发,基本订立累死rails的action和method的基调,我的想法基本是这样的:

action 基类通过基类虚函数达到初始化用户数据的功能(需要用户处理的接口)比如:
abstract class baseBeforeProcess(){
abstract doprocess();
}

接下来是model这是比较复杂的玩意,但利用类似rals的模式也就是类名=表名,关系配置和全自动化的数据对象包装

userManager,这是一个权限控制类,这是我认为比较需要的一个东西,大多数应用都有权限控制,但目前我们的设计都比较混乱,还不如集成到框架

urlProcess,这是一个全局方法类似rails的url处理器,拥有自定义url的功能,在我的理想中它具有完全的自动控制能力。

view层,目前php下使用smarty,但我个人很推荐rails的helper,helper的实质是多次模板和子模板解析实现这样的功能模型,这对于页面控制和简化模板有很大的作用,但必须实现对smarty的无修改植入,貌似smarty的新版本有插件模块应该可以比较轻松实现这样的功能,而这样模板中将会使用很多很多共用模块,而由于helper的存在可以极大减少逻辑代码在模板中出现(个人觉得如果模板中使用了比较多的逻辑运算,那么模板使用显然是失败的)

天生反转的PHP

[不指定 2007/09/04 09:46 | by edwardproAdmin ]

模仿rails的方法构造php的简单框架非常方便,由于php拥有变量函数这一特征对于在其他语言中很复杂实现的IOC在php中过于容易了,当然这也是php本身俄脚本特性所决定的,不知道效率如何。个人觉得php将来的发展指向应该是类ruby的语言,否则恐怕生命难以持久啊。

不爱报错的php

[不指定 2007/09/04 09:44 | by edwardproAdmin ]

对于类来说php本身支持确实不够好,而一些类的特性支持几乎就是僵持,上次说到过它的try catch需要自己throw才能捕获,相信这样的try catch只是形式上的东西不会有人真正去使用它的。而它的类其他特性也基本上属于形式级别的,它不爱报错宁愿执行非预期结果的特性实在令我用惯java后无法适应,比如:
把默认构造隐藏之后,在其子类中没有实现父类的构造居然是不报错的。。。另外对于类型同样会自动适应特别是任意东西转向string几乎是自动而默认的,而这经常产生非预期结果。

PHP形同虚设的TRY CATCH

[不指定 2007/08/30 19:07 | by edwardproAdmin ]
试用了一把php的try catch极其失望,除了名字相同,其他的。。。比如:

try{
    if(class_exists($act['action'])){
     $obj=new $act['action']($act,$this->_pDate);
    }else{
     throw new Exception("");
    }
   }catch (Exception $e){
    die("System error for wrong action mapping for this application");
   }

居然需要自行throw。。。这就完全失去了try catch真正的意图了。。。

原因很清楚php是一种不允许错的语言,他的语句是“没有错误”的概念,所以try catch也就成了摆设。。。

php不好用之二

[不指定 2007/08/28 17:45 | by edwardproAdmin ]
当出现嵌套require的时候,路径居然不能统一,必须用dirname来得到绝对路径。这就带来了另外一个问题,我一直以为php这类东西是文本引用然后统一编译的,事实来看他不是的,它是各自编译然后在组合的,所以才会有嵌套之后的路径错位导致必须使用绝对路径。

array_rand 真是个烂函数

[不指定 2007/08/28 00:35 | by edwardproAdmin ]

今天使用了下php的rand,首先要suck下php的伪随机函数,这是一个我没法用的函数,当然你可以觉得很方便,但问题是无法特别随机。

接下来说说array_rand,这个函数是从数组里随机拿出n个单元,看起来很容易却因为php的可变类型突然变得奇怪:

$a=array();
array_rand($source,1);

这样写没有问题吧,问题却来了,$a不是一个数组了!这真是。。。害得代码要判断传入的数量是否是1.。。真是对php的类型很不适应。
分页: 2/2 第一页 上页 1 2 最后页 [ 显示模式: 摘要 | 列表 ]