很多用过Discuz!、WordPress、ECSHOP等开源网站的人都感觉它们很好,但是自己想做一些改动或二次开发,却感觉困难重重,无从下手。很多用过Laravel,thinkPHP等框架的都觉得很方便,但是也只懂得简单调用而已,不乏做PHP开发但入行不深的Coder。究其原因,还是不了解其中原理。
本教程旨在由浅入深,教你学会其中原理,能自己开发一个简单的框架,日后有开发产品给他人使用的能力。
适用对象:有一定面向对象知识基础但是入行不深的同仁。
一. 从MVC结构开始
开源框架,无一例外都使用MVC开发模式。网上关于MVC的概念解释很多,如果你看了还不太了解,也很正常,多数解释都晦涩难懂,可以先不必理会,按照我们的思路一步步往下做,然后再回头看,你肯定对MVC有更透彻的理解。
首先我们严格按照MVC思想进行目录组织。
在web项目根目录新建三个文件夹:
— models
—views
—controllers
然后再在根目录新建文件index.php
index.php是整个web应用的入口点,所有请求都会经过它,它通过获取用户传递的参数,分别指派给不同controllers执行,controllers再调用models进行数据处理(通常是对数据库或文件的操作),然后再经views的文件显示结果,大致就是这个流程。
现在根目录的应该是这样的
--- models ---views ---controllers ---index.php
二. 定义一些常用的全局常量。
在index.php中写上以下代码
<?php //web应用的根目录
define("SERVER_ROOT", dirname(__FILE__));
//设置域名
define('SITE_ROOT' , 'http://你的域名'); //如define('SITE_ROOT' , 'https://blog.mosang.net'),以下演示均用https://blog.mosang.net表示域名,在实际操作中,请把此域名更改为您绑定的域名或者IP
?>
这样整个应用中访问在它之中定义的这些变量。
三. 建立路由文件
在controllers目录下新建一个文件,名字为“router.php”(当然你可以任意命名),这个文件用来处理所有页面请求,我们通常称为路由文件。它就像你家里的路由器,它负责把宽带分发到家中的每台电脑。router.php文件将会获取传入到index.php的页面请求,然后把请求分派给不同的控制器(controllers)。
我们现在假定用户通过index.php?channel=photo&content=latest连接来访问(channel=news表示图片频道,content=latest表示最近一次发布的内容)
在router.php输入以下代码
<?php
$channel = $_GET["channel"];
$action = $_GET["content"];
echo("您访问的频道是".$channel."<br>");
echo("请求的内容是".$content);
?>
在index.php中引入这个路由文件:
<?php
/**
* 定义文档路径
*/
define("SERVER_ROOT", dirname(__FILE__));
define('SITE_ROOT' , 'https://blog.mosang.net');
/**
* 引入router.php
*/
require_once(SERVER_ROOT . '/controllers/' . 'router.php');
?>
在浏览器地址栏中输入 https://blog.mosang.net/index.php?channel=photo&content=latest
得到的页面结果如下:
您访问的频道是photo
请求的内容是latest
四. 建立路由执行文件
通过上面的代码,我们可以获取用户提交的Addr中要访问的频道,假设频道有photo,news、about等多个频道,我们希望不同请求调用不同文件来处理。
在controllers文件夹中新建一个文件 photo.php,并输入以下代码:
<?php
//定义一个输出当前访问频道名的类
class photo_Controller {
var $channelname;
function showcurrent($channelname) {
this.$channelname = $channelname;
echo("您正在访问的频道是:".$channelname);
}
}
?>
同时,我们修改router.php的代码,如下:
<?php
$channel = $_GET["channel"]; //获取频道名
$action = $_GET["action"];
$channelFile = SERVER_ROOT . '/controllers/'.$channel . ".php";//频道名对应的php文件
if (file_exists($channelFile)) {
include_once ($channelFile);//频道名对应的php文件引入
$channelclass = $channel . "_Controller";
if (class_exists($channelclass)) {
$controller = new $channelclass; //创建实例
$controller->showcurrent($channel); //输出入当前频道名
} else {
die("不存在该频道的类!");
}
} else {
die("不存在您请求的频道!");
}
?>
目前为止,整个目录文件如下:
--- models ---views ---controllers --- photo.php --- router.php ---index.php
我们一样在浏览器地址栏中输入 https://blog.mosang.net/index.php?channel=photo&content=latest,运行结果如下:
您正在访问的频道是:photo
下面我们把photo.php复制一份,放在photo.php同一目录下,文件名更改为news.php,把news.php中的类名”photo_Controller”更改为”news_Controller”,其他不变:
<?php
class news_Controller {
var $channelname;
function showcurrent($channelname) {
this.$channelname = $channelname;
echo("您正在访问的频道是:".$channelname);
}
}
?>
我们在浏览器中输入 https://blog.mosang.net/index.php?channel=news&content=latest,运行结果如下:
您正在访问的频道是:news
目前为止,我们实现了根据参数不同,调用不同的控制器。