最近想学习php的mvc结构,在网上找了一些资料,可是大部分都是相同的,或者写的不是很满意。接着看了一个cakephp的框架,感觉太多的函数了,让人觉得就是一个记函数的过程,所以觉得不是很好。
我对mvc的理解是:c负责分配任务,协调m和v。用户发出请求时,c把请求分配给模型m,模型从数据库处理查询或者其他的一些数据操作,然后把数据返回给c,c再把数据传递给相应的v,再在前台显示。这有个比喻较好,当我们去餐馆吃饭时,招待×××就相当于c,她把客户的请求传达给厨师m,厨师把做好的菜再给×××,×××把菜再端给顾客。。。。。。。
现在我把自己的做的一个mvc介绍下:
我的访问网址是这种类型:http://www.example.com/index.php?controller/action/id:2/page:3
其中controller是控制器的名字,action是控制器下的动作名称,而action以后的参数,如id:2,page:3等是额外的参数,我们称之为params。
好了,接下来就是怎么解析这个URL,把它分化成controller,action,params。
首先说一下目录结构,
index.php 这是入口文件,用户要访问的每一个页面都要经过它
.htaccess 这是.htaccess文件
app app目录
app/controllers 控制器目录,其中文件名都是nameController的形式,类名和文件名相同,类中的动作名为nameAction的 形式
app/views 视图的目录,这里我借用smarty模板
app/views/cache
app/views/templates 模板文件
app/views/confgs
app/views/templates_c 以上三个目录是与smarty一致的,具体可以参考smarty手册
app/models 模型存放目录
core 核心文件目录
core/ini.php 初始化处理
core/config.php 一些配置文件
core/dbconfig.php 数据库的配置文件
core/dispatcher.php 分发路由
core/router.php URL处理文件
core/loader.php
core/initializer.php 包含一些文件
core/lib
core/lib/appController.php 父控制器
core/lib/appView.php 视图类,主要继承smarty文件
core/lib/appModel.php 父模型类,连接数据库
core/lib/dataAccess.php 数据库的一些基本操作
core/lib/smarty smary的核心文件,完全照搬smarty的libs文件,但将其中的Smarty.class.php重命名为Smarty.php,主要是为了自动化类。
以上就是要用到的目录文件
下面看index.php
//index,php
<?php
include("core/ini.php"); initializer::initialize(); $router = loader::load("router"); dispatcher::dispatch($router); ?>先慢慢解释。。。。。。。。。。
看ini.php
//ini.php
<?php
header("Content-type:text/html;charset=utf-8"); set_include_path(get_include_path() . PATH_SEPARATOR . "core"); //将要用到的文件包含进来 function __autoload($object){ require_once("{$object}.php"); } ?>其中__autoload函数很重要,当我们要初期化类时,如果当前文件没有,它就会自动去包含文件中寻找该类。在这里我把类名和文件名设为相同,这比较方便,比如initializer::initialize();此时就会去包含文件中查找initializer.php文件,然后初始化类initializer,再调用它的静态方法initialize();
接着看看initializer.php
//initializer.php
<?php
class initializer { public static function initialize() { set_include_path(get_include_path().PATH_SEPARATOR . "core/lib"); set_include_path(get_include_path().PATH_SEPARATOR . "app/controllers"); set_include_path(get_include_path().PATH_SEPARATOR."app/models"); set_include_path(get_include_path().PATH_SEPARATOR."app/views"); set_include_path(get_include_path().PATH_SEPARATOR."core/lib/smarty"); } } ?> 这是一个把我们将要用到的文件包含进来,目的是方便我们初始化类方便。//loader.php
<?php
class loader { private static $loaded = array(); public static function load($object){ $valid = array( "library", "view", "model", "helper", "router", "config", "hook", "cache", "db"); if (!in_array($object,$valid)){ throw new Exception("Not a valid object '{$object}' to load"); } if (empty(self::$loaded[$object])){ self::$loaded[$object]= new $object(); } return self::$loaded[$object]; } } ?>//router.php
<?php
class router { private $route; private $controller; private $action; private $params; public function __construct() { $path = array_keys($_GET);//取得URL?以后的字符串:controller/action/id:2/page:3 if (!isset($path[0])){ $path[0] = "index";//如果没有控制器名称。则调用index控制器 } $route= $path[0]; $this->route = $route; $routeParts =preg_split("",$route);//用“/"划分进数组 $this->controller=$routeParts[0];//控制器名称 $this->action=isset($routeParts[1])? $routeParts[1]:"index";//动作名称,默认是index array_shift($routeParts); array_shift($routeParts); $a=$routeParts; $b=array(); foreach($a as $aa) {$c=explode(':',$aa); $b[$c[0]]=isset($c[1])?$c[1]:$c[0]; } $this->params=$b;//此时为数组的形式Array ( [id] => 2 [page] => 3 ) } public function getAction() { if (empty($this->action)) $this->action="index"; return $this->action; } public function getController() { return $this->controller; } public function getParams() { return $this->params; } } ?>再看看dispatcher.php
//dispatcher.php
<?php
class dispatcher { public static function dispatch($router) { ob_start();//打开缓冲区 $controller =($router->getController()).'Controller';//控制器类或者控制器的文件名 $action = ($router->getAction()).'Action';//控制器的动作函数名 $params = $router->getParams(); //print_r($params); $controllerfile = "app/controllers/{$controller}.php"; if (file_exists($controllerfile)){ require_once($controllerfile); $app = new $controller();//实例化该控制器 $app->params=$params; $app->$action();//调用该动作函数 $output = ob_get_clean(); echo $output;//输出到浏览器 }else{ throw new Exception("Controller not found"); } } } ?>下面看看index控制器怎么样
//indexController.php
<?php
class indexController extends appController { public function indexAction() {$this->view->assign('test','hello,world!');
$this->view->display('index.tpl'); } } ?>这里有一个appController父类,我们看看它怎么样
//appController.php
<?php
class appController { var $model; var $view; var $params; function __construct() { $this->model=new appModel(); $this->view=new appView(); } } ?>appController主要初始化父类模型和视图,所以接着看看appModel类和appView类是个什么样
//appView.php
<?php
class appView extends Smarty { //var $smarty; function __construct() { $this->smarty; $this->template_dir = 'app/views/templates/'; $this->compile_dir = 'app/views/templates_c/'; $this->config_dir = 'app/views/configs/'; $this->cache_dir = 'app/views/cache/'; } } ?>appView主要就是重新包装一下smarty模板
//appModel.php
<?php
require_once('/dbconfig.php'); class appModel extends dataAccess { function __construct() {parent::__construct(DB_HOST,DB_USER,DB_PASSWORD,DB_DATABASE); } } ?>这里负责一些数据库的链接操作,其中dbconfig.php为
//dbconfig.php
<?php
define('DB_HOST','127.0.0.1'); define('DB_USER','root'); define('DB_PASSWORD','min'); define('DB_DATABASE','sdw'); define('CHAR_SET','utf8'); ?>appModel又继承了类文件dataAccess.php,这是数据库处理的一些文件,包括数据库链接,查询等等。。。。。这里就不列出了。
所以现在来看indexController中的动作indexAction中的 $this->view->assign('test','hello,world'); 和$this->view->display('index.tpl');,他们分别是调用父类appController的$this->view类,而$this->view类就是appView类,即smarty类,所以smarty类的assign和display方法应该很熟悉的。
在app/views/templates下建立文件index.tcp
//index.tcp
{$test}