+ -
当前位置:首页 → 问答吧 → 小恺教你写一个属于自己的MVC框架-更新完毕

小恺教你写一个属于自己的MVC框架-更新完毕

时间:2009-08-18

来源:互联网

在开始之前需要同学们知道的知识

1.php基础知识

2.单一入口, 不知道的可以看看这里 (http://www.php100.com/html/webkaifa/PHP/PHP/2009/0819/3199.html)

具备以上两点, 那我们就可以开始啦. 哈哈!

先来说一下程序的执行流程

首先有个入口文件, 然后初始化一些程序, 之后根据请求调用不同的类和方法

首先我们弄一个入口文件 Index.php 来看看代码

复制代码
  1. <?php
  2. require "Init.php";
  3. $control = new Controller();
  4. $control->Run();
  5. ?>


代码没什么特别的, 首先先引入Init.php文件 然后实例化一个类

然后调用该类的Run()方法 这里我们把这个类叫做控制器

既然引入了Init.php文件, 那么我们继续看看Init.php文件的源码


复制代码
  1. <?php
  2. header("Content-type:text/html;charset=utf-8");
  3. !defined('ROOT_PATH') && define('ROOT_PATH', str_replace('\\', '/', dirname(__FILE__)));
  4. require ROOT_PATH . '/Core/Config.php'; //引入配置文件
  5. require ROOT_PATH . '/Core/Controller.class.php'; //引入控制器类文件
  6. require ROOT_PATH . '/Core/View.class.php'; //视图类文件
  7. require ROOT_PATH . '/Core/Model.class.php'; //模型类文件
  8. ?>


分析一下代码, 如果你懂了, 可以略过这一步, 继续往下看哦.

首先 设置字符集, 然后判断如果没有定义常量"ROOT_PATH"那么就定义它

然后就是引入一些文件, 首先是配置文件, 控制器类文件, 视图类文件, 模型类文件

同理既然引入了文件,那么我们就打开文件看看代码, 先来看Config.php文件

复制代码
  1. <?php
  2. $C = array(
  3. 'URL_MODE' => 1, //URL模式, 1普通模式, 2 PATH_INFO模式
  4. 'DEFAULT_CONTROL' => 'welcome', //默认调用的控制器
  5. 'DEFAULT_ACTION' => 'index', //默认执行的方法
  6. );
  7. ?>


没什么特别的就是一个数组, 有三个值, 暂时先这样, 以后有需要在来增加

那么好, 我们继续看Controll.class.php

复制代码
  1. <?php
  2. class Controller
  3. {
  4. public function Run()
  5. {
  6. $this->Analysis(); //开始解析URL获得请求的控制器和方法
  7. $control = $_GET['c'];
  8. $action = $_GET['a'];
  9. //这里构造出控制器文件的路径
  10. $controlFile = ROOT_PATH . '/Controllers/' . $control . '.class.php';
  11. if(!file_exists($controlFile)) //如果文件不存在提示错误, 否则引入
  12. {
  13. exit('控制器不存在' . $controlFile);
  14. }
  15. include($controlFile);
  16. $class = ucwords($control); //将控制器名称中的每个单词首字母大写,来当作控制器的类名
  17. if(!class_exists($class)) //判断类是否存在, 如果不存在提示错误
  18. {
  19. exit('为定义的控制器类' . $class);
  20. }
  21. $instance = new $class(); //否则创建实例
  22. if(!method_exists($instance, $action)) //判断实例$instance中是否存在$action方法, 不存在则提示错误
  23. {
  24. exit('不存在的方法' . $action);
  25. }
  26. $instance->$action();
  27. }
  28. /**
  29. * 解析URL获得控制器与方法
  30. *
  31. * @access protected
  32. * @return void
  33. */
  34. protected function Analysis()
  35. {
  36. global $C; //包含全局配置数组, 这个数组是在Config.ph文件中定义的
  37. if($C['URL_MODE'] == 1) //如果URL模式为1 那么就在GET中获取控制器, 也就是说url地址是这种的[url=http://localhost/index.php?c]http://localhost/index.php?c[/url]=控制器&a=方法
  38. {
  39. $control = !empty($_GET['c']) ? trim($_GET['c']) : '';
  40. $action = !empty($_GET['a']) ? trim($_GET['a']) : '';
  41. }
  42. else if($C['URL_MODE'] == 2) //如果为2 那么就是使用PATH_INFO模式, 也就是url地址是这样的 [url=http://localhost/index.php/]http://localhost/index.php/[/url]控制器/方法/其他参数
  43. {
  44. if(isset($_SERVER['PATH_INFO']))
  45. {
  46. //$_SERVER['PATH_INFO']URL地址中文件名后的路径信息, 不好理解, 来看看例子
  47. //比如你现在的URL是 [url=http://www.php100.com/index.php]http://www.php100.com/index.php[/url] 那么你的$_SERVER['PATH_INFO']就是空的
  48. //但是如果URL是 [url=http://www.php100.com/index.php/abc/123]http://www.php100.com/index.php/abc/123[/url]
  49. //现在的$_SERVER['PATH_INFO']的值将会是 index.php文件名称后的内容 /abc/123/
  50. $path = trim($_SERVER['PATH_INFO'], '/');
  51. $paths = explode('/', $path);
  52. $control = array_shift($paths);
  53. $action = array_shift($paths);
  54. }
  55. }
  56. //这里判断控制器的值是否为空, 如果是空的使用默认的
  57. $_GET['c'] = $control = !empty($control) ? $control : $C['DEFAULT_CONTROL'];
  58. //和上面一样
  59. $_GET['a'] = $action = !empty($action) ? $action : $C['DEFAULT_ACTION'];
  60. }
  61. }
  62. ?>


注释写的很清楚, 这里我就不多说了, 做到这, 你就可以建立一个Controller目录, 然后在目录中建立welcome.class.php文件

写入如下内容

复制代码
  1. <?php
  2. class Welcome
  3. {
  4. public function index()
  5. {
  6. echo 'Hello';
  7. }
  8. }
  9. ?>


允许程序你将会看到Hello

然后在写一个方法
复制代码
  1. <?php
  2. class Welcome
  3. {
  4. public function index()
  5. {
  6. echo 'Hello';
  7. }
  8. public function show()
  9. {
  10. echo '方法名称Show';
  11. }
  12. }
  13. ?>


再次运行程序, 将url地址改为

http://你的域名/index.php/welcome/show/

你会看到 '方法名称Show'

好了, 看到这里我们的控制器其实已经弄得差不多了

今天先弄到这里

明天我们继续View.class.php 视图类文件, 和在welcome.class.php控制器中调用视图


程序源码, 回复后下载吧!

Demo1.zip (7 K) 下载次数:361
[ 此帖被xiaokai在2009-10-29 22:40重新编辑 ]

作者: xiaokai   发布时间: 2009-08-18

上集说到控制器, 现在我来看看视图基类
复制代码
  1. <?php
  2. class View
  3. {
  4.     protected $vars = array();
  5.     protected function assign()
  6.     {
  7.     }
  8.     protected function display()
  9.     {
  10.     }
  11. }
  12. ?>

是不是很熟悉这两个方法, 呵呵, 用来给模板设置变量和显示模板的. 和smarty一样, $vars属性是用来保持模板变量的数组, 我来写完它.
先看看assign方法
复制代码
  1. <?php
  2.     public function assign($var, $value)
  3.     {
  4.         if(is_array($var))
  5.         {
  6.             $this->vars = array_merge($this->vars, $var);
  7.         }
  8.         else
  9.         {
  10.             $this->vars[$var] = $vaule;
  11.         }
  12.     }
  13. ?>

很简单, 首先有两个参数 $var模板变量名称, $value对应的值
先判断$var是否是数组, 如果是那么将他于属性$vars合并
将$var当作下标$value当作值, 添加到属性$vars中
在来看display方法
复制代码
  1. <?php
  2.     public function display($file)
  3.     {
  4.         include(ROOT_PATH . '/Core/Template.class.php');
  5.         $this->template      = Template::GetInstance();
  6.   $this->template->templatePath   = ROOT_PATH . '/Views/';
  7.   $this->template->cache     = TRUE;
  8.   $this->template->cachePath    = ROOT_PATH . '/Cache/';
  9.   $this->template->cacheLifeTime   = 1;
  10.   $this->template->templateSuffix  = '.html';
  11.   $this->template->leftTag   = '{';
  12.   $this->template->rightTag   = '}';
  13.         $templateFile                       = ROOT_PATH . '/Views/' . $file . '.html';
  14.         if(!file_exists($templateFile))
  15.         {
  16.             exit('模板文件' . $file . '不存在');
  17.         }
  18.         $this->template->display($file, $this->vars);
  19.     }
  20. ?>

这个看上去有点多, 不着急我们慢慢解释
首先有一个参数 $file 模板文件名称, 不包括路径以及后缀
然后引入模板类, 设置模板的参数
先设置模板文件目录, 然后是否开启缓存, 然后缓存目录, 缓存有效时间, 模板文件后缀, 左右定界符
然后组合出模板文件路径 比如你传入的$file值是index 那么就是对应的模板文件就是  模板目录/index.html
然后判断模板文件是否存在, 不存在则提示错误
然后在调用模板类实例的display方法将模板文件名称, 和模板变量传入
这里这个模板类我就不多说了, 如果有兴趣的朋友可以下载附件查看, 类中有详细注视
这里既然设置了两个目录, 那么我们就去创建它, 在程序根目录下建立 Views 和 Cache 两个目录, 后面会用到
现在我们打开昨天写好的 Controller.class.php 控制器类 在里面加入一个属性 和 几个方法
复制代码
  1. <?php
  2.     protected $view = NULL;
  3.     public function __construct()
  4.     {
  5.         //实例化上面写到的视图类
  6.         $this->view = new View();
  7.     }
  8.     public function assign($var, $value = '')
  9.     {
  10.         $this->view->assign($var, $value);
  11.     }
  12.     public function display($file)
  13.     {
  14.         $this->view->display($file);
  15.     }
  16. ?>

现在进入到Views目录中建立一个模板命名为index.html 内容如下
复制代码
  1. <html>
  2. <head>
  3.     <title>{$title}</title>
  4. </head>
  5. <body>
  6. {$body}
  7. </body>
  8. </html>

控制器类中也有assign方法, 他是调用构造函数中创建的view类实例的assign方法
也就是我们上面定义的那个 dispaly方法也一样
现在我们打开welcome.class.php文件, 修改index方法, 注意这里好要将Welcome类继承自Controller类
复制代码
  1. <?php
  2. class Welcome extends Controller
  3. {
  4. public function index()
  5. {
  6.         $this->assign('title', 'Hello World');
  7.         $this->assign('body', '小恺教你写一个属于自己的MVC框架');
  8.         $this->display('index');
  9. }
  10. }
  11. ?>

现在你需要做的就是打开浏览器, 在地址栏中输入 http://yourdomain/Index.php 然后你将会看到 "小恺教你写一个属于自己的MVC框架"
如果出现了这行字, 那么恭喜你View层也搞定了, 明天我们继续 小恺教你写一个属于自己的MVC框架之模型
如果你没看懂这篇文章也可以联系 QQ 601200376  Email [url=mailto:[email protected]][email protected][/url]
最后希望大家多多支持... 哈哈
广告一下 Tomorrow Framework 0.1

测试版 以经快完工了, 想看看的朋友可以联系我,  "源文件有详细注视哦!!!"


程序源码, 回复后下载吧...

Demo.rar (13 K) 下载次数:274
[ 此帖被xiaokai在2009-08-19 13:45重新编辑 ]

作者: xiaokai   发布时间: 2009-08-18

好几天没上啦, 实在对不住大家..

接着上集,今天我们来说模型的实现.

在Core目录中建立 Model.class.php 文件, 然后建立一个Model类

复制代码
  1. <?php
  2. class Model
  3. {
  4. //数据库连接句柄
  5. protected $dbLink = NULL;
  6. }
  7. ?>


现在来给他添加方法

复制代码
  1. <?php
  2. /**
  3.   * 构造器, 连接数据库
  4.   *
  5.   * @access public
  6.   * @return void
  7.   */
  8. public function __construct()
  9. {
  10.   global $C;
  11.   $this->dbLink = mysql_connect($C['DB_HOST'], $C['DB_USER'], $C['DB_PWD']) or exit(mysql_error());
  12.   mysql_select_db($C['DB_NAME'], $this->dbLink) or exit(mysql_error());
  13.   mysql_query("SET NAMES {$C['DB_CHAR']}");
  14. }
  15. /**
  16.   * 执行SQl命令
  17.   *
  18.   * @access public
  19.   * @param  string  $sql
  20.   * @return resource
  21.   */
  22. public function Query($sql)
  23. {
  24.   $res = mysql_query($sql) or exit(mysql_error());
  25.   return $res;
  26. }
  27. /**
  28.   * 执行SQl命令,返回是否执行成功
  29.   *
  30.   * @access public
  31.   * @param  string  $sql
  32.   * @return bool
  33.   */
  34. public function Execute($sql)
  35. {
  36.   if(mysql_query($sql))
  37.   {
  38.    return TRUE;
  39.   }
  40.   return FALSE;
  41. }
  42. /**
  43.   * 返回处理后的结果集
  44.   *
  45.   * @access public
  46.   * @param  resource $res 结果集
  47.   * @return mixed
  48.   */
  49. public function Fetch($res, $type = 'array')
  50. {
  51.   $func = $type == 'array' ? 'mysql_fetch_array' : 'mysql_fetch_object';
  52.   $row  = $func($res);
  53.   return $row;
  54. }
  55. ?>


这几个方法很简单, 就是一般的mysql操作. 不过多解释

现在打开Config.php把内容改为

复制代码
  1. <?php
  2. $C = array(
  3. 'URL_MODE'     => 2,    //URL模式, 1普通模式, 2 PATH_INFO模式
  4. 'DEFAULT_CONTROL'   => 'welcome',  //默认调用的控制器
  5. 'DEFAULT_ACTION'   => 'index',   //默认执行的方法
  6. 'DB_HOST'     => 'localhost',  //mysql主机
  7. 'DB_USER'     => 'root',   //mysql用户
  8. 'DB_PWD'     => '',    //mysql密码
  9. 'DB_CHAR'     => 'utf8',   //字符集
  10. 'DB_NAME'     => 'test',   //使用的数据库
  11. );
  12. ?>


然后在打开Controller.class.php 控制器基类 在里面加一个方法, 用来加载模型

复制代码
  1. <?php
  2. protected function LoadModel($modelName)
  3. {
  4.   $modelFile = ROOT_PATH . '/Models/' . $modelName . '.class.php';   //构造模型文件路径
  5.   !file_exists($modelFile) && exit('模型' . $modelName . '不存在');  //如果模型文件不存在提示错误
  6.   include($modelFile);              //存在, 则引入
  7.   $class = ucwords($modelName);           //获得模型类名
  8.   !class_exists($class) && exit('模型' . $modelName . '未定义');;  //判断是否定义了模型类, 如果没有提示错误
  9.   $model = new $class();             //实例化模型类
  10.   return $model;               //返回实例
  11. }
  12. ?>


注释很详细也不做解释了. 现在在根目录下家里Models目录, 然后建立一个 test.class.php文件

内容很简单, 继承自Model类就行了

复制代码
  1. <?php
  2. class Test extends Model
  3. {
  4. }
  5. ?>


然后在自定义的控制器welcome.class.php中修改index方法

复制代码
  1. <?php
  2. public function index()
  3. {
  4.   $model = $this->LoadModel('test');  //载入模型
  5.   $res    = $model->Query("SELECT * FROM reg"); //查询表, 这里查询你有的表就行了
  6.   $row    = $model->fetch($res);  //处理结果集返回数组
  7.   print_r($row);       //打印出来
  8. }
  9. ?>


这样模型也搞定了, 这里只是是抛砖引玉, 不对的地方希望大家指出.

知道大概后你可以自己扩展, 比如做出多语言, 数据库抽象层, 等等等...

Demo.rar (16 K) 下载次数:1245
[ 此帖被xiaokai在2009-08-28 15:35重新编辑 ]

作者: xiaokai   发布时间: 2009-08-18

完整目录结构

├─Core
├─Controllers
├─Views
├─Cache
└─Models

带文件的目录结构
│  Description.php
│  Index.php
│  Init.php
│  Desription2.php
│  Desription3.php

├─Core
│      Config.php
│      Controller.class.php
│      View.class.php
│      Template.class.php
│      Model.class.php

├─Controllers
│      welcome.class.php

├─Views
│      index.html

├─Cache
│      6a992d5529f459a44fee58c733255e86.php

└─Models
        test.class.php
[ 此帖被xiaokai在2009-08-28 15:41重新编辑 ]

作者: xiaokai   发布时间: 2009-08-18

继续占楼...

作者: xiaokai   发布时间: 2009-08-18

我是来学习的。

作者: moro   发布时间: 2009-08-18

呵呵小凯不错!不顶不行了!此贴必火!   

作者: tslongpk1   发布时间: 2009-08-19

呵呵小凯不错

作者: xiukan   发布时间: 2009-08-19

我来学习啦~~

作者: xlmxbg   发布时间: 2009-08-19

引用
引用第7楼xiukan于2009-08-19 11:27发表的 :
呵呵小凯不错


呵呵, 你打错我名字了, 我叫小恺.

作者: xiaokai   发布时间: 2009-08-19

引用
引用第6楼tslongpk1于2009-08-19 09:55发表的 :
呵呵小凯不错!不顶不行了!此贴必火!   


呵呵, 你也打错了哦.  让大火来的更猛烈些吧. 哈哈

作者: xiaokai   发布时间: 2009-08-19

挺好的帖子!LZ辛苦了

作者: gaoxu387   发布时间: 2009-08-19

引用
引用第11楼gaoxu387于2009-08-19 12:12发表的 :
挺好的帖子!LZ辛苦了


为人民服务, 哈哈 

作者: xiaokai   发布时间: 2009-08-19

look

作者: qicto   发布时间: 2009-08-19

不是一般的强!!!!

支持!!

作者: garygay   发布时间: 2009-08-19

支持lz 我来学习了

作者: 263290692   发布时间: 2009-08-20

引用
引用第9楼xiaokai于2009-08-19 12:01发表的  :


呵呵, 你打错我名字了, 我叫小恺.

记下了

作者: xiukan   发布时间: 2009-08-21

呵呵,支持小恺,还是要更新哦!

作者: skyandlw   发布时间: 2009-08-21

纯支持

作者: skyandlw   发布时间: 2009-08-21

别因为某些人不喜欢顶贴就停止更新呀,
像张老师那样就算不顶贴,论坛人气在不好,他的教程也是照样的做下去;
把帖子设置成隐藏这样就好多了.相信肯定能顶上去的.
别忘了有我在支持着你呢.
把你的技术跟我们分享一下吧.
我也想写个属于自己的mvc!
hoho.我喜欢偷窃别人的技术.嘎嘎嘎嘎!

作者: 叶子   发布时间: 2009-08-22

引用
引用第19楼叶子于2009-08-22 23:53发表的 :
别因为某些人不喜欢顶贴就停止更新呀,
像张老师那样就算不顶贴,论坛人气在不好,他的教程也是照样的做下去;
把帖子设置成隐藏这样就好多了.相信肯定能顶上去的.
别忘了有我在支持着你呢.
把你的技术跟我们分享一下吧.
.......


呵呵, 好的, 谢谢叶子. 

明天继续更新, 我重新弄, 这个仿佛不怎么样...

作者: xiaokai   发布时间: 2009-08-23

学习!!

作者: chenfu12   发布时间: 2009-08-23

半夜3点还上网.真头子
给你个健康表吧
一、晚上9-11点为免疫系统(淋巴)排毒时间,
此段时间应安静或听音乐 。
二、晚间11-凌晨1点,肝的排毒,需在熟睡中进行。
三、凌晨1-3点,胆的排毒,亦同。
四、凌晨3-5点,肺的排毒。此即为何咳嗽的人在这段时间咳得最剧烈,因排毒动作已走到
肺;不应用止咳药,以免抑制废积物的排除。
五、凌晨5-7点,大肠的排毒,应上厕所排便。
六、凌晨7-9点,小肠大量吸收营养的时段,应吃早餐。疗病者最好早吃,在6点半前,养生
者在7点半前,不吃早餐者应改变习惯,即使拖到9、10点吃都比不吃好。
* 七、半夜至凌晨4点为脊椎造血时段,必须熟睡,不宜熬夜。 *
珍爱生命,合理作息!,以后不要熬夜了!

作者: 叶子   发布时间: 2009-08-23

还是没搞清楚C和M的关系。。。。。

作者: cain   发布时间: 2009-08-23

不得不钦佩xiaokai同学!

作者: daodao   发布时间: 2009-08-23

不顶不行了!此贴必火

作者: uncleliu   发布时间: 2009-08-23

我也是来学习感觉是太高深了,

作者: wall123   发布时间: 2009-08-24

一定要看看

作者: 檀木屑   发布时间: 2009-08-24

小恺,不要停止更新啊,我支持你!~

作者: kook   发布时间: 2009-08-24

顶上去!

作者: kook   发布时间: 2009-08-25