在PHP中应用MVC的介绍(二)
(Walter.Fan编译自Jason E. Sweat写的An Introduction to MVC Using PHP)
下面来看一个简单的MVC应用程序实例:
说得天花乱坠,不如实际动和做个简单的例子.在这个例子中,我们以Phrame框架来
实现MVC模式. Phrame是Jakarta Struts的一个PHP实现方案,它的控制文件不象struts
那样是XML文件,而是PHP中最常用的数组.
在Phrame中,和Struts一样,通过Action, Forms and Forwards这几个类
将模型和视图松散耦合在一起.
每一次controller初始化,它都会创建一个扩展自Action类的子类的实例
controller会调用你的Action子类的Process()方法,
一个Forwards的列表和一个包含所有HTTP request 变量的Form对象
你的Action的期望结果是去确定适当的Forward对象返回给controller.
controller会处理这个Forward对象并退出对于这次请求的处理过程
Action对象的作用,可以以它自己在HTTP request 和一个句子之间做一个类比
你可以认为在这个句子中,Action是一个动词, Model是一个名词, View是一个形容词.
换句话说,一个特定的Web请求会在一个Model(名词)上执行一个Action(动词),
或者显示一个View来描述(形容词)一个Model(名词)
这个类比描述了Action和Model关系,在选择对象名时可以加以考虑
这个例子是Phrame的Hello World例子的一个修改版本 (http://phrame.itsd.ttu.edu/).
源代码可由http://sourceforge.net/projects/phrame下载
在这个例子中,我去掉了PHP的一些警告 ,用Smarty代替XSLT来格式化视图
MVC应用程序使用一个引导(bootstap)文件,它是一个单独的PHP文件,是应用程序的核心
本例中,这个bootstap文件是hello.php,让我们来看看这个bootstap文件
<?
error_reporting(E_ALL);
define('PHRAME_LIB_PATH', '../../phrame/');
require_once PHRAME_LIB_PATH.'include.jes.php';
require_once 'Smarty.class.php';
require_once 'MappingManager.php';
require_once 'actions/HelloAction.php';
require_once 'models/Person.php';
require_once 'models/HelloErrors.php';
define('APPL_VIEW', 'hello.php?'._VIEW.'=');
define('APPL_ACTN', 'hello.php');
?>
在一个Phrame程序中,Forms, Actions and Forwards的关系是
在传统的Phrame选项数组中建立的.我觉得这个数组单调冗长不利于开发和维护
就创建了一个MappingManager类来管理维护这些关系
这个类可以被任一个Phrame应用程序扩展,它有方法可返回
Phrame使用的PHP数组.
这个类的好处是在你增加它们进可以验证Form和action mapping之间的关系
(避免了在你尝试使用Phrame选项数组时产生错误)
class HelloMap extends MappingManager
{
function HelloMap()
{
//set options
$this->_SetOptions('handle_error');
//add application forms
$this->_AddForm('helloForm','ActionForm');
//add application actions and forwards
$this->_AddMapping('sayHello','HelloAction', APPL_VIEW.'index','helloForm');
$this->_AddForward('sayHello', 'index');
$this->_AddForward('sayHello', 'hello',APPL_VIEW.'hello');
}
}
在 HelloMap class的构造函数中完成了我们所要做的.
首先,重载传统的Phrame选项数组,我们定义了一个错误处理函数
接着,看需要识别什么Form,在这个例子中,不需要扩展标准的Phrame ActionForm类
最后,定义actions和forwards, 本例中,只有一个action: sayHello
两个Forwards:“index” 和 “hello”
MappingManager::_AddMapping() 方法的参数是
(mapping的名字, 实现这个mapping的类, 调用action的缺省地址,mapping中与action关联的form)
MappingManager::_AddForward()方法的参数是
action mapping 的标识符,forward的标识符和可选的重定向URL(如果没有action与之关联)
<?
session_start();
$smarty =& new Smarty;
$map =& new HelloMap;
$controller =& new ActionController($map->GetOptions());
$errors =& new HelloErrors;
function handle_error($number, $message, $file,$line, $context)
{
appl_error($message);
}
function appl_error($psErrorMsg)
{
$errors =& new HelloErrors;
$errors->AddError($psErrorMsg);
}
?>
接下来,我们start the session, 创建几个我们要用到的对象
Smarty template object
HelloMap class object(我们先前定义的)
Phrame ActionController Object
(它需要一个选项数组,可由MappingManager::GetOptions()获得)
这节的代码还加入了一个错误Model,封装了错误处理实际上的实现方案
(保存错误在$_SESSION的一个数据中, 参见HelloErrors.php)
并定义了两个函数
appl_error(),允许你增加一个错误到系统的错误对象中去
handle_error() 一个PHP错误处理函数,它调用了函数appl_error()
这就是说,你可以直接用函数appl_error(),或者用
trigger_error()(如果PHP的错误处理句柄设成handle_error())
<?
if (array_key_exists(_ACTION,$_REQUEST))
{
//release control to controller for
//further processing
$controller->Process($map->GetMappings(),
$_REQUEST);
}
else
{
//determine and display view
$requested_view = (array_key_exists(_VIEW,
$_REQUEST)) ?
strtolower($_GET[_VIEW]) :
'index';
switch ($requested_view) {
case 'hello':
$template = $requested_view.'.tpl';
//assign view specific data
$person =& new Person;
$smarty->Assign('name',
$person->GetName());
break;
case 'index':
default:
$template = 'index.tpl';
}
//assign common data
$smarty->Assign(array(
'appl_link' => APPL_ACTN
,'appl_view' => APPL_VIEW
,'action' => _ACTION
));
//assign and clear errors
$smarty->Assign('errors',
$errors->GetErrors());
$smarty->Display($template);
exit;
}
余下的代码实现了MVC的controller组件
if语句判断是否请求了一个action.
如果是的,调用Phrame
ActionController::Process()方法激活这个框架.
如果没有指定的请求,显示一个View
else语句确定合适的View,
assign特定的数据到smarty模板
assign通用的数据到smarty模板
处理任何可能发生的错误
然后render渲染模板
跳出这个程序,我们来看看到底我们的应用程序中加入什么东西来使用Phrame
首先, 要考虑如果根本没有参数传入,我们的应用程序该干什么.
在本例中,跳过action处理,渲染index.tpl模板以显示缺省的视图
这儿是Smarty template index.tpl

