这个教程能够使大家掌握用mvc模式开发php应用的基本概念。此教程分为三个部分。如今这篇是第一部分。

如今市面上有非常多流行的框架供大家使用。可是我们也能够自己动手开发一个mvc框架。採用mvc模式能够大大降低我们开发应用的时间,并且能够更好的组织项目源码,并且当中的某些模块还可在其他项目中使用。如今我要教大家写一个简单的mvc框架。因为这个项目非常easy,轻量。所以可能并非最佳实践,也不具备安全性。还须要大家在实际应用中完好。

所用技术:php,面向对象开发方法。

開始

首先在站点根文件夹下建立三个文件夹

  • models
  • views
  • controllers

然后在根文件夹下新建一个文件:

  • index.php

如今项目结构应该像这样

§ 站点根文件夹

§ index.php

§ models/

§ views/

§ controllers/

index.php是整个web应用的入口点,全部的用户请求都会经过它。

我们会写一些代码来把用户请求分派到对应的控制器中,这些控制器存放在controllers目录里。之后。我们就能够用以下的方式来实现页面跳转:

  • http://你的域名.com/index.php?

    page1

  • http://你的域名.com/index.php?

    page2

  • http://你的域名.com/index.php?page3

设置前端控制器index.php

首先在index.php中定义站点根文件夹和站点域名,以便在整个应用中訪问。

[php] view plain copy
  1. <?

    php

  2. //应用的根文件夹就是index.php的父文件夹
  3. define("SERVER_ROOT", dirname(__FILE__));
  4. //你的域名.comm 是你的server域名
  5. define('SITE_ROOT' , 'http://你的域名.com');

定义了站点根文件夹后,在不论什么php文件里。都能非常方便的引用其他文件夹的php文件,由于index.php是入口文件,这样就行在整个应用中訪问在它之中定义的这些变量。

设置路由器router.php(转发用户请求到对应控制器)

在controllers文件夹下新建一个文件。名字为“router.php",这个文件用来处理全部页面请求。想像一下你家里的路由器。它负责把internet路由到家中的每一个电脑。

router.php文件将会获取传入到index.php的页面请求。然后把请求分派给不同的控制器(controllers)。

route.php中的代码:

[php] view plain copy
  1. <?

    php

  2. //获取全部请求
  3. $request = $_SERVER['QUERY_STRING'];

这句代码会获取传入到应用中的请求參数。QUERY_STRING就是”?“后面的全部字符串。

  • http://你的域名.com/index.php?page1
上面的地址会在代码中得到”page1&action=login“,为了把page1和后面的參数分开,我们须要在route.php中继续增加下列代码:
[php] view plain copy
  1. //解析$request变量。得到用户请求的页面(page1)和其他GET变量(&分隔的变量)如一个请求http://你的域名.com/index.php?page1&article=buildawebsite,则被解析为array("page1", "article=buildawebsite")
  2. $parsed = explode('&' , $request);
  3. //用户请求的页面,如上面的page1,为$parsed第一个变量,shift之后。数组为array("article=buildawebsite")
  4. $page = array_shift($parsed);
  5. //剩下的为GET变量。把它们解析出来
  6. $getVars = array();
  7. foreach ($parsed as $argument)
  8. {
  9. //用"="分隔字符串,左边为变量,右边为值
  10. list($variable , $value) = split('=' , $argument);
  11. $getVars[$variable] = $value;
  12. }
  13. //这是測试语句,一会儿会删除
  14. print "The page your requested is '$page'";
  15. print '<br/>';
  16. $vars = print_r($getVars, TRUE);
  17. print "The following GET vars were passed to the page:<pre>".$vars."</pre>";

如今我们须要在index.php中引入route.php

[php] view plain copy
  1. <?php
  2. /**
  3. * 定义文档路径
  4. */
  5. define("SERVER_ROOT", dirname(__FILE__));
  6. define('SITE_ROOT' , 'http://你的域名.com');
  7. /**
  8. * 引入router.php
  9. */
  10. require_once(SERVER_ROOT . '/controllers/' . 'router.php');
  11. ?

    >

假设顺利的话,你能够打开浏览器输入:

  • http://你的域名.com/index.php?

    news&article=howtobuildaframework

我们会看到例如以下输出
[html] view plain copy
  1. The page you requested is 'news'
  2. The following GET vars were passed to the page:
  3. Array
  4. (
  5. [article] => howtobuildaframework
  6. )

假设没有上述输出,请检查你的server配置是否正确。并检查代码是否有错误。

如今来让我们加入一个页面到我们的站点里,这样就能够让router.php来产生一个页面。而不是直接输出上面的信息。
创建一个控制器(controller)
在controllers目录里新建一个文件名称为“news.php",定义例如以下的类:
[php] view plain copy
  1. <?

    php

  2. /**
  3. * 这个文件处理文章的查询。并提供文章
  4. */
  5. class News_Controller
  6. {
  7. /**
  8. * $template变量会保存与此控制器相关的"view(视图)"的文件名称,不包含.php后缀
  9. */
  10. public $template = 'news';
  11. /**
  12. * 此方法为route.php默认调用
  13. *
  14. * @param array $getVars 传入到index.php的GET变量数组
  15. */
  16. public function main(array $getVars)
  17. {
  18. //測试代码,以后会删除
  19. print "We are in news!";
  20. print '<br/>';
  21. $vars = print_r($getVars, TRUE);
  22. print
  23. (
  24. "The following GET vars were passed to this controller:" .
  25. "<pre>".$vars."</pre>"
  26. );
  27. }
  28. }


注意我们把route.php中的測试代码复制过来了。并做了一些改动,我们把它放置在main函数里。如今让我们来改动route.php中的代码:

[php] view plain copy
  1. <?php
  2. /**
  3. * 此文件会把全部的传入參数分派到对应的控制器中
  4. */
  5. //获取请求參数
  6. $request = $_SERVER['QUERY_STRING'];
  7. //解析请求页面和其他GET变量
  8. $parsed = explode('&' , $request);
  9. //页面是第一个元素
  10. $page = array_shift($parsed);
  11. //剩余的为GET变量,也把它们解析出来
  12. $getVars = array();
  13. foreach ($parsed as $argument)
  14. {
  15. //split GET vars along '=' symbol to separate variable, values
  16. list($variable , $value) = split('=' , $argument);
  17. $getVars[$variable] = $value;
  18. }
  19. //构成控制器文件路径
  20. $target = SERVER_ROOT . '/controllers/' . $page . '.php';
  21. //引入目标文件
  22. if (file_exists($target))
  23. {
  24. include_once($target);
  25. //改动page变量,以符合命名规范(如$page="news",我们的约定是首字母大写,控制器的话就在后面加上“<strong>_Controller”</strong>,即News_Controller)
  26. $class = ucfirst($page) . '_Controller';
  27. //初始化相应的类
  28. if (class_exists($class))
  29. {
  30. $controller = new $class;
  31. }
  32. else
  33. {
  34. //类的命名正确吗?
  35. die('class does not exist!');
  36. }
  37. }
  38. else
  39. {
  40. //不能在controllers找到此文件
  41. die('page does not exist!');
  42. }
  43. //一但初始化了控制器,就调用它的默认函数main();
  44. //把get变量传给它
  45. $controller->main($getVars);?>

再次訪问http://你的域名.com/index.php?

news&article=howtobuildaframework,你将会看到从News_Controller打印出来的信息。

注意。我们如今用die()来处理错误。我们能够用其他更好的错误处理来规制它。但如今使用die()足够了,试试訪问其他页面如http://你的域名.com/index.php?books,你会看到"page does not exist!"错误。创建一个Model(模型)完好News_Controller。如果我们有一些新闻片段来供读者阅读。那么就须要News_Controller这个控制器去调用一个模型来抓取相关的新闻片段,不管它们是存储在数据库还是文件中。

在models目录里新建一个文件,“news.php”,代码例如以下:

[php] view plain copy
  1. <?php
  2. /**
  3. * 新闻模型为新闻控制器做复杂的后台操作
  4. */
  5. class News_Model
  6. {
  7. public function __construct()
  8. {
  9. print 'I am the news model';
  10. }
  11. }

如今,我们须要对新闻控制器稍做一些更改,打开controllers里的news.php,把News_Controller类的main函数的代码改为例如以下,这样。我们就会在“News_Model”初始化时,看到打印在屏幕上的信息:
[php] view plain copy
  1. public function main(array $getVars)
  2. {
  3. $newsModel = new News_Model;
  4. }

如今刷新页面,你会看到:

[php] view plain copy
  1. Fatal error: Class 'News_Model' not found in /var/www/mvc/controllers/news.php on line xx

等一下,这不是我们想要的结果。我们正试图去载入一个不存在的类。

那么原因就是我们并没有引入/models/news.php文件。为了解决问题,让们又一次来看一下router.php。然后在它的顶部加入一些代码:

[php] view plain copy
  1. //当类初始化时,自己主动引入相关文件
  2. function __autoload($className)
  3. {
  4. //解析文件名称,得到文件的存放路径,如News_Model表示存放在models目录里的news.php(这里是作者的命名约定)
  5. list($filename , $suffix) = split('_' , $className);
  6. //构成文件路径
  7. $file = SERVER_ROOT . '/models/' . strtolower($filename) . '.php';
  8. //获取文件
  9. if (file_exists($file))
  10. {
  11. //引入文件
  12. include_once($file);
  13. }
  14. else
  15. {
  16. //文件不存在
  17. die("File '$filename' containing class '$className' not found.");
  18. }
  19. }

这个函数重载了PHP内置的autoload函数。当我们试图去初始化一个不存在的类时,这个‘魔术方法’同意我们拦截php所运行的动作。

通过使用__autoload函数,我们可以告诉php寻找包括此类的文件的位置。如果你遵循了这篇文章中类和文件名称的命名约定,那么每当你初始化一个类时,你就不必手动去引入包括此类的文件了!

保存route.php,再刷新一次浏览器,你会看到:
[html] view plain copy
  1. I am the news model
让我们在新闻模型类里定义一些函数来提供文章。如今,我们仅仅简单的定义了一个数组。并保存一些文章,然后提供一个函数。让控制器从中依据标题获取一篇文章。改动models/news.php:
[php] view plain copy
  1. <?php
  2. /**
  3. * 新闻模型为新闻控制器做复杂的后台操作
  4. *
  5. */
  6. class News_Model
  7. {
  8. /**
  9. * 文章数组. key为文章标题, 值为对应的
  10. * 文章。
  11. */
  12. private $articles = array
  13. (
  14. //文章1
  15. 'new' => array
  16. (
  17. 'title' => 'New Website' ,
  18. 'content' => 'Welcome to the site! We are glad to have you here.'
  19. )
  20. ,
  21. //2
  22. 'mvc' => array
  23. (
  24. 'title' => 'PHP MVC Frameworks are Awesome!' ,
  25. 'content' => 'It really is very easy. Take it from us!'
  26. )
  27. ,
  28. //3
  29. 'test' => array
  30. (
  31. 'title' => 'Testing' ,
  32. 'content' => 'This is just a measly test article.'
  33. )
  34. );
  35. public function __construct()
  36. {
  37. }
  38. /**
  39. * 依据标题获取文章
  40. *
  41. * @param string $articleName
  42. *
  43. * @return array $article
  44. */
  45. public function get_article($articleName)
  46. {
  47. //从数组中获取文章
  48. $article = $this->articles[$articleName];
  49. return $article;
  50. }
  51. }?>

如今改动controllers/news.php中的main函数:

[php] view plain copy
  1. public function main(array $getVars)
  2. {
  3. $newsModel = new News_Model;
  4. //获取一篇文章
  5. $article = $newsModel->get_article('test');
  6. print_r($article);
  7. }

如今我们并没有考虑过滤用户输入的问题。由于我们如今仅仅是为了尽快让大家掌握PHP MVC的基本内容。所以我们如今不必太关心这些。

假设訪问例如以下网址:

§ http://yourdomain.com/mvc/index.php?

news&article=test

你会看到例如以下输出:

[html] view plain copy
  1. Array ( [title] => Testing [content] => This is just a measly test article. )

创建视图(VIEW

如今我们已经有控制器和模型了,仅仅差一个视图。

视图是表现层,它是你的应用中。与用户接触最频繁的部分。之前我提到过,视图是提供与业务逻辑分离的用户接口。有非常多方法能够做到这个。你能够使用模板引擎Smarty或其他类似的。你也能够写一个自己的模板引擎,但那肯定是相当艰巨的任务。最后。你能够使用原生php视图。

对于眼下来说。php视图足够了。这个就像曾经php与html代码混合编程一样,可是有一点不同是,我们的业务逻辑已经和视图分离了。看一下例如以下代码:

[php] view plain copy
  1. <html>
  2. <head></head>
  3. <body>
  4. <h1>Welcome to Our Website!</h1>
  5. <hr/>
  6. <h2>News</h2>
  7. <h4><?

    =$data['title'];?></h4>

  8. <p><?

    =$data['content'];?></p>

  9. </body>
  10. </html>

注意,嵌入的php标签利用了PHP 快捷操作符。

这样就行把我们的内容直接输出到HTML里面了。

在views目录里新建一个文件“news.php”,把上述代码拷贝进来。如今我们有了视图文件,可是我们须要一个与视图交互的方法。在models目录里新建一个文件“view.php”,加入例如以下代码:

[php] view plain copy
  1. <?php
  2. /**
  3. * 在我们的MVC框架中,处理视图的功能
  4. */
  5. class View_Model
  6. {
  7. /**
  8. * 保存赋给视图模板的变量
  9. */
  10. private $data = array();
  11. /**
  12. * 保存视图渲染状态
  13. */
  14. private $render = FALSE;
  15. /**
  16. * 载入一个视图模板
  17. */
  18. public function __construct($template)
  19. {
  20. //构成完整文件路径
  21. $file = SERVER_ROOT . '/views/' . strtolower($template) . '.php';
  22. if (file_exists($file))
  23. {
  24. /**
  25. * 当模型对象销毁时才干渲染视图
  26. * 假设如今就渲染视图,那么我们就不能给视图模板赋予变量
  27. * 所以此处先保存要渲染的视图文件路径
  28. */
  29. $this->render = $file;
  30. }
  31. }
  32. /**
  33. * 接受从控制器赋予的变量。并保存在data数组中
  34. *
  35. * @param $variable
  36. * @param $value
  37. */
  38. public function assign($variable , $value)
  39. {
  40. $this->data[$variable] = $value;
  41. }
  42. public function __destruct()
  43. {
  44. //把类中的data数组变为该函数的局部变量,以方便在视图模板中使用
  45. $data = $this->data;
  46. //渲染视图
  47. include($this->render);
  48. }
  49. }

如今,最后一件要做的事就是从News_Controller里载入视图。改动controllers/news.php:

[php] view plain copy
  1. <?php
  2. /*
  3. *这个文件处理文章的查询。并产生新闻文章*
  4. */
  5. class News_Controller{
  6. /**
  7. * $template变量会保存与此控制器相关的"view(视图)"的文件名称,不包含.php后缀
  8. *
  9. */
  10. public $template = 'news';
  11. /**
  12. * 此方法为route.php默认调用
  13. *
  14. * @param array $getVars 传入到index.php的GET变量数组
  15. */
  16. public function main(array $getVars) {
  17. $newsModel = new News_Model;
  18. //获取一片文章
  19. $article = $newsModel->get_article($getVars['article']);
  20. //创建一个视图。并传入该控制器的template变量
  21. $view = new View_Model($this->template);
  22. //把文章数据赋给视图模板
  23. $view->assign('title' , $article['title']);
  24. $view->assign('content' , $article['content']);
  25. }
  26. }
  27. ?>

开发自己的PHP MVC框架(一)相关推荐

  1. Android的MVC框架

    http://www.cnblogs.com/wanghafan/archive/2012/07/20/2600786.html MVC是当前比较流行的框架,随便Google下,就可以发现几乎所有的应 ...

  2. php实现简单的框架,PHP 实现简单的 MVC 框架

    前言: 在 PHP 的世界中,有着众多的框架,它们各有所长,各具特色.既有 Zend,Symfony,Laravel 等大型框架,也有 CodeIgniter,Slim Framework 等轻量级的 ...

  3. 搭建一个简单的MVC框架

    背景 为何要用MVC框架?首先我们知道不用框架的话,在javaweb项目中每个请求都要写一个servlet,并且要在web.xml中对每个servlet类的映射作配置,不方便开发,因此引入MVC框架. ...

  4. portlet java_[Java] 使用 Spring 2 Portlet MVC 框架构建 Portlet 应用

    Spring 除了支持传统的基于 Servlet 的 Web 开发之外,也支持 JSR 168 Portlet 的开发.Spring Portlet MVC 框架尽可能多地继承了 Spring Ser ...

  5. 使用PHP搭建自己的MVC框架

    使用PHP搭建自己的MVC框架 一.什么是MVC MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View ...

  6. [导入]ASP.NET MVC框架开发系列课程(3):URL导向.zip(16.66 MB)

    讲座内容: ASP.NET MVC框架中一个关键特性就是基于URL的导向.本次课程将讲解URL Routing机制的使用. 课程讲师: 赵劼 MSDN特邀讲师 赵劼(网名"老赵". ...

  7. cocos2dx之lua项目开发中MVC框架的简单应用

    **************************************************************************** 时间:2015-03-31 作者:Sharin ...

  8. [导入]ASP.NET MVC框架开发系列课程(2):一个简单的ASP.NET MVC应用程序.zip(13.70 MB)...

    讲座内容: 使用ASP.NET MVC框架进行开发与ASP.NET WebForms截然不同.本次课程将通过官方的示例程序简单了解一下ASP.NET MVC应用程序的结构与特点. 课程讲师: 赵劼 M ...

  9. Node.js 国产 MVC 框架 ThinkJS 开发 config 篇

    原创:荆秀网 网页即时推送 https://xxuyou.com | 转载请注明出处 链接:https://blog.xxuyou.com/nodejs-thinkjs-study-config/ 本 ...

最新文章

  1. 数据库插入时,标识列插入显式值
  2. border-radius的兼容问题
  3. C语言链表的来源分析
  4. composer常用命令
  5. 对象的多数组表示(不一样的链表-多数组表示链表)
  6. Spark SQL(十)之基于物品的推荐公式
  7. jpa 托管_java – jpa非托管实体
  8. 一些知名科技公司的开源机器学习框架/平台
  9. 拓端tecdat|R语言用Garch模型和回归模型对股票价格分析
  10. Android按钮点击控制进度条,Android通过按钮和进度条实现音量调节(AudioManager)...
  11. IT成长中的龟兔赛跑
  12. Oralce数据库计算工作日(处理假期及加班)
  13. 四种常见的XML解析方式
  14. 什么是串口通信UART?
  15. 阿里云服务器操作系统怎么选择?
  16. 网页中插入视频与音频---HBuilder
  17. 【分享】ArcGIS实现分子分母等标注实用技巧
  18. 逆元 阶乘逆元 数论 HDU 5651 xiaoxin juju needs help
  19. Java解析接口返回的xml数据
  20. android sdk 配置出错error: unknown argument --licenses

热门文章

  1. 喝最烈的酒、挖最大的DONG——工具与技巧篇
  2. UE4: 学习虚幻引擎4的16条准则
  3. C++程序设计:原理与实践(进阶篇)15.4 链表
  4. 在CentOS安装PHP5.6
  5. 高效开发 Android App 的 10 个建议
  6. 函数遍历IOS中block的使用
  7. 第十六章 复杂的抽像类结构
  8. delphi中move函数的用法 转
  9. 推荐WCF的一系列录像
  10. kubevirt在360的探索之路(k8s接管虚拟化)