论述PHP实现MVC框架

2016-06-13 18:08张志瑜
科技视界 2016年13期
关键词:开发者调用视图

张志瑜

PHP是时下流行的动态网页开发语言之一,受到包括FACEBOOK等行业巨头在内的众多企业青睐,其实际应用非常之广。掌握基本的PHP语言有利于计算机专业学生日后从事网站维护管理的需要。然而在实际中,工业生产的潮流已经不甘于使用半成品的CMS(内容管理系统)或者WordPress,而是使用更具个性化的PHP框架来进行快速开发,掌握简单的几个函数已经难以处理日益丰富的网站开发维护需要。业界的发展潮流倾向代码和界面分离的做法使得不仅PHP程序员,甚至连前端的页面美工也需要对PHP有较为深刻的认识。

主流的PHP框架多数采用MVC框架,MVC框架把网页请求分为Controller(控制),Model(模型)和View(视图)三部分,通过减低内容模块之间的耦合度,从而简化开发流程和提高代码复用。用PHP语言来实现MVC框架可以看作是继PHP语言入门的后续课程和进阶,通过实现MVC框架来使得学生对PHP和MySQL数据库有更加具体和深刻的认识,从建立项目,解决问题中更感性地掌握PHP的用途,比面向过程式的开发更加有趣。虽然现成的MVC框架(Yii,CodeIgniter,CakePHP)为数不少,但是掌握独自开发一个完整的MVC框架能够使得开发者更加了解整套框架的运作,也能够使得开发者更快地掌握运用其他框架开发。

对于使用PHP语言来实现完整的MVC网站框架,需要开发者使用现有的工具解决好不同的类之间的控制和处理。我们大致可以根据右图提供的思路来建立MVC模型的雏形。虽然没有专业框架拥有很多处理类(缓存类,安全类,输入输出处理类),但是最基本的MVC框架然仍不能想象得过于简单,很多问题需要我们不断地思考和解决。

1 获取用户请求

用户发出的网页请求通过URL来传递,传递的思路就是把需要访问的页面分解成多个$_GET参数(如:http://localhost/account/list,控制类是account,输出list页面)。实际上网页服务器会解析成网站目录下account目录下的list页面。在实际和预设两者的歧义中,我们考虑使用.htaccess来实现请求的转化。.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网络配置,通过.htaccess文件,可以实现网页重定向,自定义错误页面,改进文件扩展名,特定用户访问权限设置,配置默认文档等功能。.htaccess建立在网站站点的目录里而不是在Apache安装目录下,它具有分布式配置的方式,在目录中可以放置一个包含一个或多个指令的文件方式,以及作用于此目录及其所有子目录。最普遍的例子是使用一下语句来实现用户请求的转义:

REWRITERULE

^(.*)$ INDEX.PHP?URL=$1

经过.htaccess处理之后,PHP会把用户的请求转化成$_GET[‘url]变量。最普遍的做法却存在一个小问题,用户输入包含后缀名的完整URL的时候(如http://localhost/account/list.php),PHP则会把list.php作为整体而不把.php作为后缀名看待。后续操作会因为找不到list.php(只有list方法)而报错。所以我们可以通过小小的修改来对请求进行细化:

REWRITERULE

^([A-ZA-Z0-9\/\-_]+)\.?([A-ZA-Z]+)?$ INDEX.PHP?URL = $1&EXTENSION = $2

经过修改后,PHP会把.php作为$_GET[‘extention]参数,则更有利于后续操作针对不同的后缀名来进行不同的处理。

2 对用户请求进行分析

无论是使用单个文件或者独立出一个路由的类,思路都是对$_GET[‘url]进行分析分拆,使用explode_array函数提取不同的部分。再以call_user_func_array()来进行控制类和方法类的调用。除了控制类参数部分和方法类参数部分,其余部分可以数组的方式调用模型类。

$RT = new Router($request);

Session::init();

$controller = $RT->getController();

$controller = new $controller;

$method = $RT->getMethod();

$params = $RT->getParams();

if (empty($params)) {

call_user_func(array($controller, $method));

} else {

call_user_func_array(array($controller, $method), $params);

}

3 控制类的设计

控制类(Controller)是MVC处理模式的主要部分,常用思路是把单一类别的网页作为类名(例如与用户有关的可以定义为account类),具体的某个页面就是类中的方法(例如查看单个用户的信息,如account类中的profile函数)。我们一般先建立一个名为Controller的抽象类,统一定义初始化函数(__construct())和主函数(index(),某个类的默认页面),具体的类则通通继承这个抽象类。

控制类不能简单的包含模型类(model)和视图类(view)两个元素,因为在常用的网站开发中往往需要Session,网页分页等支持。所以我们采用流行框架中用到load类的方法。值得一提的是,CodeIgniter不是使用Loader类而是使用指针函数来加载其他类,采用这种方法的话需要额外建立一个全局变量来存储加载了的类的指针数组。另外还可以额外加载registry类来存储加载函数,registry类作为控制类的一个元素。解决了存储加载类,我们则用家里Loader类来加载不同模块(Session,Input,Output)等。

模型类(Model类)与视图类(View类)不同,正如上图所示,模型类(Model类)并不是每个控制类都需要调用的(如只显示静态页面,或者调用缓存页面),所以通常的做法是把模型类也归纳在Loader类的调用范畴。

视图类(View类)则是必须包含的元素,因为每个控制类最终目录都是要通过调用页面(视图类,PHP页面文件)来显示。View类既可以也归纳为Loader类调用,也可以独立在Loader类之外。需要开发者考虑调用的时候考虑调用单个PHP页面还是包含额外的PHP页面模块。开发者可以根据设计思路来做出不同的选择。

abstract class Controller

{

protected $_registry;

protected $load;

public function __construct()

{

$this->_registry = Registry::getInstance();

$this->load = new Load;

}

abstract public function index();

final public function __get($key)

{

if ($return = $this->_registry->$key) {

return $return;

}

return false;

}

}

4 模型类的设计

模型类(Model类)的作用在与对数据进行处理,把数据处理的结果和分析数据返回给视图类(View类)进行显示。与控制类(Controller类)相同,我们需要先建立模型的抽象类。主要是对数据库的加载,众所周知数据库对一个动态网页是多么的重要,所以数据库的处理我们也必须使用独立的数据库类(Database类)。Database类可以是对PDO类的继承,这样方便我们快速调整不同的数据库(MySQL,SQLite等),对于只专注于某种数据库的应用,我们可以使用其特定的类(如MySQLi类)。

在Database类的方法实现中,我们建议繁琐的多次SQL操作描述成较为容易理解的操作集合函数。此外我们也可以直接使用现有的ORM库(如Redbean)来代替Database类,把ORM作为模型类(Model类)的元素。

对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。 简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。ORM提供了所有SQL语句的生成,代码人员远离了数据库概念。从一个概念需求(例如一个HQL)映射为一个SQL语句,并不需要什么代价,连1%的性能损失都没有。真正的性能损失在映射过程中,更具体地讲,是在对象实例化的过程中。

abstract class Model

{

protected $_registry;

protected $load;

public function __construct()

{

require_once CONFIG_PATH.'db.php';

$this->db = new Database($CFG['db']);

}

}

5 视图类的设计

与其说是视图类(View类),不如说是PHP页面就更为准确,视图类(View类)可以看做基本的PHP页面,控制类(Controller类)调用(require(),require_once())这些页面进行显示出最后效果。关键是需要对模型类(Model类)产生的数据进行处理在传递给View。

在MVC框架的过程中,我们可以使用Output类来辅助视图语句的输出,例如把HTML的form代码拆分成几个echo()函数。

6 使用现有的PHP库

我们已经建立一个简单的MVC框架雏形,而且可以在这个雏形之上不断的改进和赋予更加高级的特性和框架功能(Cookies,Security等)。我们发现原来很多功能,函数都可以手工去一一打造,然而在快速开发或团队开发的时候,重复的快发基本的功能模块,除了加深开发者的基本功之外,对开发帮助不大。我们的框架可以和容易的去调用现有得第三方的PHP库(如PEAR)。但是我们也需要通过类似于spl_autoload_register()去改进PHP的自动加载函数。

通过对MVC框架的实现,开发者可以加深对PHP语言认识和开拓网站开发的思路。针对于PHP初学者来说,本案例就是一门PHP动态网站开发的进阶课程。从中可以学习到PHP语言课学习中很少用到的方法:全局函数,指针函数,类,继承,抽象类等。也为日后的CodeIgniter等框架的学习打下基础。

[责任编辑:汤静]

猜你喜欢
开发者调用视图
核电项目物项调用管理的应用研究
LabWindows/CVI下基于ActiveX技术的Excel调用
视图
Y—20重型运输机多视图
SA2型76毫米车载高炮多视图
基于系统调用的恶意软件检测技术研究
iOS开发者调查
iOS开发者调查
栝楼产业开发者谢献忠
利用RFC技术实现SAP系统接口通信