miketwais

work up

自己写MVC框架

一个完整的MVC框架应该包括:M:基本数据处理功能,V:视图处理模块(模板引擎),C:控制器模块,异常处理,日志系统等等。每一个模块都需要精心设计。

今天自己写一个MVC框架,当然只是实现MVC原理的一个简单实现。

 

项目目录结构:

mymvc

--models

----news.php

----view.php

--controllers

----news.php

----router.php

--views

----news.php

index.php

设计我们的URL访问路径的结构:http://127.0.0.1/mymvc/index.php?news&article=mvc

一般框架设计采用单入口模式:即所有请求均由index.php文件来接受。

index.php的代码:

<?php
//应用的根目录就是index.php的父目录   
define("SERVER_ROOT", 'D:/wamp/www/mymvc');  

//你的域名.comm 是你的服务器域名  
define('SITE_ROOT' , '127.0.0.1/mymvc'); 

require_once(SERVER_ROOT . '/controllers/' . 'router.php');  

?>
View Code

然后添加一个路由文件router.php.用来转发用户的请求到相应的控制器。可以想象一下家里的路由器,负责将internet上的信息分发给每天电脑。这里的路由器也一样,接收来自浏览器的请求,获取参数,按规则根据参数来加载相应的控制器文件。

router.php的代码:

<?php  
/** 
 * 此文件会把所有的传入参数分派到相应的控制器中 
 */  
  
//获取请求参数  
$request = $_SERVER['QUERY_STRING'];  
  
//解析请求页面和其它GET变量  
$parsed = explode('&' , $request);  
  
//页面是第一个元素  
$page = array_shift($parsed);  
  
//剩余的为GET变量,也把它们解析出来  
$getVars = array();  
foreach ($parsed as $argument)  
{  
    //split GET vars along '=' symbol to separate variable, values  
    list($variable , $value) = explode('=' , $argument);  
    $getVars[$variable] = $value;  
}  
  
//构成控制器文件路径  
$target = SERVER_ROOT . '/controllers/' . $page . '.php';  
  
//引入目标文件  
if (file_exists($target))  
{  
    include_once($target);  
  
    //修改page变量,以符合命名规范(如$page="news",我们的约定是首字母大写,控制器的话就在后面加上“<strong>_Controller”</strong>,即News_Controller)  
    $class = ucfirst($page) . '_Controller';  
  
    //初始化对应的类  
    if (class_exists($class))  
    {  
        $controller = new $class;  
    }  
    else  
    {  
        //类的命名正确吗?  
        die('class does not exist!');  
    }  
}  
else  
{  
    //不能在controllers找到此文件  
    die('page does not exist!');  
}  
  
//一但初始化了控制器,就调用它的默认函数main();  
//把get变量传给它  
$controller->main($getVars);

//当类初始化时,自动引入相关文件  
function __autoload($className)  
{  
    //解析文件名,得到文件的存放路径,如News_Model表示存放在models文件夹里的news.php(这里是作者的命名约定)  
    list($filename , $suffix) = explode('_' , $className);  
  
    //构成文件路径  
    $file = SERVER_ROOT . '/models/' . strtolower($filename) . '.php';  
  
    //获取文件  
    if (file_exists($file))  
    {  
        //引入文件  
        include_once($file);          
    }  
    else  
    {  
        //文件不存在  
        die("File 'filename′containingclass′className' not found.");      
    }  
}  
?> 
View Code

接下来我们来实现一个简单的请求,我们模拟读取文章功能。

在models中添加news.php

这里没有实现数据库的访问,我们模拟添加几个测试的文章数据,另外添加一个读取文章的方法。

代码如下:

<?php  
/** 
 * 新闻模型为新闻控制器做复杂的后台操作 
 * 
 */  
class News_Model  
{  
    /** 
     * 文章数组. key为文章标题, 值为相应的 
     * 文章。 
     */  
    private $articles = array  
    (  
        //文章1  
        'new' => array  
        (  
            'title' => 'New Website' ,  
            'content' => 'Welcome to the site! We are glad to have you here.'  
        )  
        ,  
        //2  
        'mvc' => array  
        (  
            'title' => 'PHP MVC Frameworks are Awesome!' ,  
            'content' => 'It really is very easy. Take it from us!'  
        )  
        ,  
        //3  
        'test' => array  
        (  
            'title' => 'Testing' ,  
            'content' => 'This is just a measly test article.'  
        )  
    );  
  
    public function __construct()  
    {  
    }  
  
    /** 
     * 根据标题获取文章 
     *  
     * @param string $articleName 
     *  
     * @return array $article 
     */  
    public function get_article($articleName)  
    {  
        //从数组中获取文章  
        $article = $this->articles[$articleName];  
      
        return $article;  
    }  
  
}?>  
View Code

接下来在controllers中添加news.php控制器

控制器主要做这件事情:接收到请求后,从model获取相应数据,然后将数据传递给view.

<?php  
/** 
 * 这个文件处理文章的查询,并提供文章 
 */  
class News_Controller  
{  
    /** 
     * $template变量会保存与此控制器相关的"view(视图)"的文件名,不包括.php后缀  
     */  
    public $template = 'news';  
  
    /** 
     * 此方法为route.php默认调用 
     *  
     * @param array $getVars 传入到index.php的GET变量数组 
     */  
    public function main(array $getVars)  
{  
    $newsModel = new News_Model;  
      
    //获取一篇文章  
    $article = $newsModel->get_article('test');  
      
    print_r($article);  
}  
}  
View Code

接下来添加视图文件,在v

视图是表现层,它是你的应用中,与用户接触最频繁的部分。之前我提到过,视图是提供与业务逻辑分离的用户接口,有很多方法可以做到这个。你可以使用模板引擎Smarty或其它类似的。你也可以写一个自己的模板引擎,但那肯定是相当艰巨的任务。最后,你可以使用原生php视图。我们简单实现php视图足够了。在views文件夹中新建news.php视图文件,代码:

<html>  
    <head></head>  
    <body>  
        <h1>Welcome to Our Website!</h1>  
        <hr/>  
        <h2>News</h2>  
        
        <h4><?php echo $data['title'];?></h4>  
        <p><?php echo $data['content'];?></p>  
    </body>  
</html>  
View Code

现在有了视图文件,但是需要一个与视图交互的方法。接下来在models文件夹里新建一个文件“view.php”,添加如下代码:

<?php  
/** 
 * 在我们的MVC框架中,处理视图的功能 
 */  
class View_Model  
{  
    /** 
     * 保存赋给视图模板的变量 
     */  
    private $data = array();  
  
    /** 
     * 保存视图渲染状态 
     */  
    private $render = FALSE;  
  
    /** 
     * 加载一个视图模板 
     */  
    public function __construct($template)  
    {  
        //构成完整文件路径  
        $file = SERVER_ROOT . '/views/' . strtolower($template) . '.php';  
      
        if (file_exists($file))  
        {  
            /** 
             * 当模型对象销毁时才能渲染视图 
             * 如果现在就渲染视图,那么我们就不能给视图模板赋予变量 
             * 所以此处先保存要渲染的视图文件路径 
             */  
            $this->render = $file;  
        }          
    }  
  
    /** 
     * 接受从控制器赋予的变量,并保存在data数组中 
     *  
     * @param $variable 
     * @param $value 
     */  
    public function assign($variable , $value)  
    {  
        $this->data[$variable] = $value;  
    }  
  
    public function __destruct()  
    {  
        //把类中的data数组变为该函数的局部变量,以方便在视图模板中使用  
        $data = $this->data;  
         //print_r($data);exit();
        //渲染视图  
        include($this->render);  
    }  
}  
View Code

最后,需要在controller中加载视图,传递数据。

修改controllers/news.php中的main函数:

public function main(array $getVars)  
{  
    $newsModel = new News_Model;  
      
    //获取一篇文章  
     $article = $newsModel->get_article($getVars['article']);   
         //创建一个视图,并传入该控制器的template变量   
         $view = new View_Model($this->template);   
         //把文章数据赋给视图模板 
         $view->assign('title' , $article['title']);   
         $view->assign('content' , $article['content']);  
}     
View Code

到这里基本完成了MVC的简单实现。

现在我们访问:http://127.0.0.1/mymvc/index.php?news&article=mvc

就会看到一个显示文章信息的页面。

 

点击下载:代码下载地址

posted @ 2015-06-01 23:10  MasonZhang  阅读(230)  评论(0)    收藏  举报