1.4.3 应用(前端控制器)(1)
1.4.2节中对原有的MVC模式进行了改进,在入口文件中实现了URL的解析。用户的每一次请求都指向服务器的***可访问文件。经过解析URL,最终转向所要访问的控制器。但是当系统日趋复杂和多样时,如URL参数和POST数据需要进行必要的检查和特殊字符过滤、记录日志、访问统计等,如果各种可以集中处理的任务都放在入口文件执行,那么将会出现代码重复、业务逻辑混乱且分散的情况。因此,为了降低系统代码逻辑的复杂度,进一步集中控制系统,并提高系统的安全控制能力,以及可维护性、可重用性和可伸缩性,本节中对原有的MVC模式进行了改进,提出了应用(前端控制器)的概念,实现MVC在复杂系统中的前端控制器开发模式优化策略。
1.在应用中实现URL解析
采用前端控制器模式,提供一个处理不同请求的中心,处理工作包括安全事务、视图选择、异常处理和响应内容的生成,通过将这些处理工作集中在一点进行,大大降低了PHP代码量,同时也减少了视图层的程序逻辑,保证了在不同请求之间可以大量地重用逻辑代码。
应用(前端控制器)的URL解析功能在文件framework/Cweb- Application.php文件中实现,流程图如图1-9所示。解析URL代码如下。
- php
- class CWebApplication {
- public $name;
- //默认控制器是SiteController
- public $defaultController="site";
- //默认动作是actionIndex
- public $defaultAction="index";
- //执行应用
- public function run()
- {
- //如URL 为http://hostname/index.php?r=controllerid/actionid
- //得到controllerid/actionid
- if(!empty($_GET['r']))
- {
- $route=$_GET['r'];
- //得到controllerid 赋值给成员变量
- $pos=strpos($route,'/');
- $this->defaultController=substr($route,0,$pos);
- $this->defaultController=strtolower($this->defaultController);
- //得到actionid 赋值给成员变量
- $this->defaultAction=(string)substr($route,$pos+1);
- }
- //得到控制器类名
- $className=ucfirst($this->defaultController).'Controller';
- //获得控制器文件路径
- $classFile="./protected/controllers/".$className.'.php';
- //最后一步操作:该类文件存在及该类存在,则导入并调用acion 方法
- if(is_file($classFile))
- {
- if(!class_exists($className,false))
- {
- require($classFile);
- $class= new $className();
- $functionName="action".ucfirst($this->defaultAction);
- $class->$functionName();
- }
- }
- }
- }
2.单例模式创建应用(前端控制器设计模式)
对于系统中的某些类来说,只有一个实例很重要。例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。例如,在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行***化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此,确保系统中某个对象的***性(即一个类只能有一个实例)是非常重要的。
我们希望系统中的应用(前端控制器)只有一个实例对象而且该实例对象易于外界访问,从而方便应用实例对象个数的控制并节约系统资源,单例模式是最好的解决方案之一。
单例模式是一种常用的软件设计模式。其要点有3个:一是类只能有一个实例,二是它必须自行创建这个实例,三是它必须自行向整个系统提供这个实例。
从具体实现角度来说,就是以下3点:一是单例模式的类只提供私有的构造方法,二是类定义中含有一个该类的静态私有对象,三是该类提供静态的公有方法用于创建或获取它本身的静态私有对象。在framework/CWebApplication.php文件中添加下面所示的部分代码。
- php
- class CWebApplication {
- ……
- //定义类的静态私有对象
- private static $_app;
- //构造方法在实例对象被创建时自动执行
- private function __construct($config=null)
- {
- //获取配置文件中的数组
- }
- //静态的公有方法用于创建它本身的静态私有对象
- public static function createApplication($config=null)
- {
- if(self::$_app===null)
- self::$_app = new CApplication($config);
- return self::$_app;
- }
- //静态的公有方法用于获取它本身的静态私有对象
- public static function app()
- {
- return self::$_app;
- }
- //执行应用
- public function run(){……}
- }
3.应用的配置文件
默认情况下,应用是一个CWebApplication的实例。要自定义它,通常需要提供一个配置文件以在创建应用实例时初始化其属性值。这就好比去组装计算机,客户拿来具体的配置单,按照要求就可以组装符合要求的计算机。而CWebApplication就是组装工人,配置单就是下面要说明的配置文件。
配置信息在配置文件中以数组元素的方式存放,一个元素就是两个字符串组成的键值对,一个字符串是键(key),另一个字符串是这个键的对应的值(value)。大多数的系统都有一些配置常量,将这些常量放在配置文件中,系统通过访问这个配置文件取得配置常量,就可以通过修改配置文件而无须修改程序达到更改系统配置的目的。系统也可以在配置文件中存储一些工作环境信息,这样在系统每次访问时,这些信息可以运行在每一个应用的生命周期中。
通常在一个单独的PHP 脚本(protected/config/main.php)中保存这些配置。在脚本中,通过以下方式返回此配置数组。
- php
- return array(
- //默认控制器
- "defaultController"=>"default",
- //通过应用全局访问方法Yii::app()->name;直接访问。
- "name"=>"my application",
- );
- ?>
在应用的构造方法中添加对配置文件操作的代码:
- php
- class CWebApplication {
- ……
- //构造方法在实例对象被创建时自动执行
- private function __construct($config=null)
- {
- //获取配置文件中的数组
- if(is_string($config))
- $config=require($config);
- /*
- 把配置文件中数组定义的元素赋值给CWebApplication 类中相同成员属性
- array(
- "name"=>"my application",
- "defaultController"=>"default",
- );
- */
- if(is_array($config))
- {
- /*
- 第一次循环:$this->name=“my application”;
- 第二次循环:$this->defaultController=“default”;
- */
- foreach($config as $key=>$value)
- $this->$key=$value;
- }
- }
- ……
- }
喜欢的朋友可以添加我们的微信账号:
51CTO读书频道二维码
51CTO读书频道活动讨论群:365934973