这个教程能够使大家掌握用mvc模式开发php应用的基本概念。此教程分为三个部分。如今这篇是第一部分。
如今市面上有非常多流行的框架供大家使用。可是我们也能够自己动手开发一个mvc框架。採用mvc模式能够大大降低我们开发应用的时间,并且能够更好的组织项目源码,并且当中的某些模块还可在其他项目中使用。如今我要教大家写一个简单的mvc框架。因为这个项目非常easy,轻量。所以可能并非最佳实践,也不具备安全性。还须要大家在实际应用中完好。
所用技术: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
-
-
-
define("SERVER_ROOT", dirname(__FILE__));
-
-
-
define(‘SITE_ROOT‘ , ‘http://你的域名.com‘);
定义了站点根文件夹后,在不论什么php文件里。都能非常方便的引用其他文件夹的php文件,由于index.php是入口文件,这样就行在整个应用中訪问在它之中定义的这些变量。
设置路由器router.php(转发用户请求到对应控制器)
在controllers文件夹下新建一个文件。名字为“router.php",这个文件用来处理全部页面请求。想像一下你家里的路由器。它负责把internet路由到家中的每一个电脑。
router.php文件将会获取传入到index.php的页面请求。然后把请求分派给不同的控制器(controllers)。
route.php中的代码:
-
<?
php
-
-
-
$request = $_SERVER[‘QUERY_STRING‘];
这句代码会获取传入到应用中的请求參数。QUERY_STRING就是”?“后面的全部字符串。
- http://你的域名.com/index.php?page1
上面的地址会在代码中得到”page1&action=login“,为了把page1和后面的參数分开,我们须要在route.php中继续增加下列代码:
-
-
$parsed = explode(‘&‘ , $request);
-
-
-
$page = array_shift($parsed);
-
-
-
$getVars = array();
-
foreach ($parsed as $argument)
-
{
-
-
list($variable , $value) = split(‘=‘ , $argument);
-
$getVars[$variable] = $value;
-
}
-
-
-
print "The page your requested is ‘$page‘";
-
print ‘<br/>‘;
-
$vars = print_r($getVars, TRUE);
-
print "The following GET vars were passed to the page:<pre>".$vars."</pre>";
-
如今我们须要在index.php中引入route.php
-
<?php
-
-
-
-
define("SERVER_ROOT", dirname(__FILE__));
-
define(‘SITE_ROOT‘ , ‘http://你的域名.com‘);
-
-
-
-
require_once(SERVER_ROOT . ‘/controllers/‘ . ‘router.php‘);
-
?
>
假设顺利的话,你能够打开浏览器输入:
我们会看到例如以下输出
-
The page you requested is ‘news‘
-
The following GET vars were passed to the page:
-
-
Array
-
(
-
[article] => howtobuildaframework
-
)
-
假设没有上述输出,请检查你的server配置是否正确。并检查代码是否有错误。
如今来让我们加入一个页面到我们的站点里,这样就能够让router.php来产生一个页面。而不是直接输出上面的信息。
创建一个控制器(controller)
在controllers目录里新建一个文件名称为“news.php",定义例如以下的类:
-
<?
php
-
-
-
-
class News_Controller
-
{
-
-
-
-
public $template = ‘news‘;
-
-
-
-
-
-
-
public function main(array $getVars)
-
{
-
-
print "We are in news!";
-
print ‘<br/>‘;
-
$vars = print_r($getVars, TRUE);
-
print
-
(
-
"The following GET vars were passed to this controller:" .
-
"<pre>".$vars."</pre>"
-
);
-
}
-
}
注意我们把route.php中的測试代码复制过来了。并做了一些改动,我们把它放置在main函数里。如今让我们来改动route.php中的代码:
-
<?php
-
-
-
-
-
-
$request = $_SERVER[‘QUERY_STRING‘];
-
-
-
$parsed = explode(‘&‘ , $request);
-
-
-
$page = array_shift($parsed);
-
-
-
$getVars = array();
-
foreach ($parsed as $argument)
-
{
-
-
list($variable , $value) = split(‘=‘ , $argument);
-
$getVars[$variable] = $value;
-
}
-
-
-
$target = SERVER_ROOT . ‘/controllers/‘ . $page . ‘.php‘;
-
-
-
if (file_exists($target))
-
{
-
include_once($target);
-
-
-
$class = ucfirst($page) . ‘_Controller‘;
-
-
-
if (class_exists($class))
-
{
-
$controller = new $class;
-
}
-
else
-
{
-
-
die(‘class does not exist!‘);
-
}
-
}
-
else
-
{
-
-
die(‘page does not exist!‘);
-
}
-
-
-
-
$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
-
-
-
-
class News_Model
-
{
-
public function __construct()
-
{
-
print ‘I am the news model‘;
-
}
-
}
如今,我们须要对新闻控制器稍做一些更改,打开controllers里的news.php,把News_Controller类的main函数的代码改为例如以下,这样。我们就会在“News_Model”初始化时,看到打印在屏幕上的信息:
-
public function main(array $getVars)
-
{
-
$newsModel = new News_Model;
-
}
如今刷新页面,你会看到:
-
Fatal error: Class ‘News_Model‘ not found in /var/www/mvc/controllers/news.php on line xx
-
等一下,这不是我们想要的结果。我们正试图去载入一个不存在的类。
那么原因就是我们并没有引入/models/news.php文件。为了解决问题,让们又一次来看一下router.php。然后在它的顶部加入一些代码:
-
-
function __autoload($className)
-
{
-
-
list($filename , $suffix) = split(‘_‘ , $className);
-
-
-
$file = SERVER_ROOT . ‘/models/‘ . strtolower($filename) . ‘.php‘;
-
-
-
if (file_exists($file))
-
{
-
-
include_once($file);
-
}
-
else
-
{
-
-
die("File ‘$filename‘ containing class ‘$className‘ not found.");
-
}
-
}
这个函数重载了PHP内置的autoload函数。当我们试图去初始化一个不存在的类时,这个‘魔术方法’同意我们拦截php所运行的动作。
通过使用__autoload函数,我们可以告诉php寻找包括此类的文件的位置。如果你遵循了这篇文章中类和文件名称的命名约定,那么每当你初始化一个类时,你就不必手动去引入包括此类的文件了!
保存route.php,再刷新一次浏览器,你会看到: