查看文章 |
理想的Controller
2009年05月25日 星期一 下午 7:40
作者:老王 现有的PHP框架,如CakePHP,其Controller的运作模式基本是类Rails的方式: class ArticlesController extends AppController { function index() {} function view() {} function add() {} function edit() {} function delete() { if ($this->Article->del($this->params['id'])) { $this->redirect(array('action'=>'index')); } } } 这样的Controller很难透明扩展,主要存在以下问题: 一:当一个请求到达时,比如说是delete,框架会实例化ArticlesController,然后调用delete方法,控制器里的其它代码如index, view, add, edit, delete,都是和delete无关的,对PHP这样的脚本语言来说,每个请求都需要重新初始化环境,从严格意义上讲,任何不必要的多余代码对性能都是有害的。 二:当处理redirect的时候,由于Action一般没有形参,也没有返回值,只能使用的是直接跳转的方式,相当于在方法里硬编码了exit(),这无疑是坏味道,如果我们想用Filter机制扩展delete的话,由于exit()的存在,后面的代码根本没有机会执行,扩展也就不可能了。 如果我设计PHP框架,我会这样设计Controller: class DeleteController extends Controller implements Executable { protected $filters = array('Transaction'); public function execute($request, $response) { // $request->getParams('id'); $response->setStatus('307 Temporary Redirect'); } } 一:一个Action就是一个Controller,多个Action文件可以放到一个文件夹里以模块方式存在。 二:对于redirect,不存在硬编码exit,而是引入response对象,在前端控制器里根据状态码来控制跳转。 乍一看上去,这样的Controller设计方式类似于Java,但用意有些许不同。在Java的一些框架中,如Struts,虽然也把request,response作为Controller形参,但之所以这样做是因为request,response都是有状态的,通过剥离它们,Controller对象本身就变成了无状态的,从而可以在各个请求间得以复用。但是PHP每次请求都要重新建立运行环境,所以本质上是不可能在各个请求间复用Controller对象的,对PHP而言,真正的意义在于,这样的设计给了Controller更灵活,更透明的扩展方式,比如说透明事务处理: class TransactionFilter extends Decorator implements Executable { public function execute($request, $response) { try { // Transaction begin $this->Controller->execute($request, $response); // Transaction commit } catch (Exception $e) { // Transaction rollback } } } 在前端控制器里,利用装饰器等模式,可以很容易的把Controller和Filter整合到一起(参考链接),从而透明的给DeleteController加上事务处理的功能,类似的,还可以透明的加上更多的Filter,从而给了Controller无限扩展的能力。 |
最近读者:

