开发框架的定义我没有找到很准确的描述,下面几句话基本归纳了开发框架的的功能和用途php
简而言之,框架就是制定一套规范或者规则(思想),你们(程序员)在该规范或者规则(思想)下工做。或者说就是使用别人搭好的舞台,你来作表演。css
优势:上面说过,框架其实就是别人把一些基础的代码给封装成库,让程序员来调用,例如表单验证、文件上传、验证 码之类的基础功能;框架还把程序的设计架构给肯定了,因此程序员只需按照框架规定的方法来写上本身的核心代码,程序就能基本成型了。因此应用PHP开发框 架可使程序员只需专一于应用的核心代码,基础代码可直接调用框架的类库,并且框架的设计架构能够保证团队开发时代码的一致性,因此能够大大提升WEB应 用开发的效率。mysql
缺点:这世界什么东西都不是完美的,因此利用框件架开发有利也有弊。PHP框架缺点就是过度封装了PHP的基础 函数,对与一个PHP新手来讲,他可能不须要学习PHP的任何基础函数,仅靠翻阅框架的说明文档和调用框架封装好的接口就能完成一个完整的PHP应用程 序,从某方面说这样能够下降PHP应用开发的技术要求,可是这样对于学习来讲是不利的,最后会致使过于依赖开发框架。在一个论坛里看到这样一句话评论 PHP开发框架:程序员
学之者生,用之者死
MVC是软件工程中的一种软件架构模式,MVC把软件系统分红三个基本部分:模型(Model)、视图(View)和控制器(Controller)。web
模型(Model)“数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。 “模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操做。可是模 型中数据的变化通常会经过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图能够了解在数据模型上发生 的改变。sql
视图(View) 视图层可以实现数据有目的的显示(理论上,这不是必需的)。在视图中通常没有程序上的逻辑。为了实现视图上的刷新功能,视图须要访问它监视的数据模型(Model),所以应该事先在被它监视的数据那里注册。数据库
控制器(Controller) 控制器起到不一样层面间的组织做用,用于控制应用程序的流程。它处理事件并做出响应。“事件”包括用户的行为和数据模型上的改变。数组
MVC在WEB应用程序中应用较普遍,右图是一个基于MVC的WEB请求处理过程。php框架
首先,用户发送一个请求给控制器(Controller),控制器根据用户的请求向数据模型(Model)发送数据需求,数据模型根据需求进行相应 的数据处理(如访问数据库、进行相应的计算等)后,把数据结果传回控制器,控制器获得数据后,就能够调用视图(View),生成一个页面,返回给用户。安全
上面说了那么多,下面咱们动手开发一个简单的PHP框架程序,框架听起来好像挺复杂的,其实仍是很简单的,只要弄懂了它的思想就没有问题。咱们框架的名字就叫small-framework吧。
咱们知道PHP每次接收到请求时都要初始化所有资源,处理完毕后再释放所有的资源,PHP框架也是如此。框架接收到用户的请求后,须要一个初始化的 过程,在初始化时实例化框架的核心模块,而后在把请求传送给框架的相应模块进行处理。由于不可能全部的请求都使用同一个控制器,除非程序功能很是简单,所 以在初始化完成后,咱们还须要根据用户的请求来调用相应的控制器,因此咱们须要一个分发器(Dispatcher)来对用户的请求进行分发。在控制器里, 咱们就能够调用数据模型和视图来处理用户的请求了。
上面粗略的分析了用户请求的处理流程,下面进行更加精细的分析
从上面的分析能够知道,要处理用户的请求须要先初始化框架的核心模块,如分发器模块,因此用户的请求首先须要被重定向至一个初始化页面,重定向能够 使用.htaccess文件来实现,在咱们这个框架里,咱们首先把全部的请求都重定向至index.php里,在index.php里面完成初始化操做: 初始化核心模块,咱们还能够在初始化时读入框架的配置文件信息,而后调用分发器把请求分发到相应的控制器,实例化这个控制器,并调用控制器中的方法来处理 用户的请求。在控制器里,咱们能够获取用户的输入,判断用户的请求,而后调用相应的数据模型进行数据处理,控制器获得数据后,把数据传给视图,视图根据得 到的数据返回一个页面给用户,请求结束。
根据上面的分析,咱们能够列出small-framework的文件结构
Core/ 框架的核心模块
Dispatcher.php
View.php
Controller/ 自定义的控制器
有了以上的分析,框架工做的基本流程咱们基本清楚了,下面咱们就按照请求的处理顺序来开始编码
首先是.htaccess文件,
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase /small-framework #基于框架的根目录进行重定向 RewriteCond %{REQUEST_FILENAME} !-f #若是用户请求的不是一个文件 RewriteCond %{REQUEST_FILENAME} !-d #若是用户请求的不是一个目录 RewriteRule . index.php [L] #则重定向至index.php </IfModule>
如今若是用户不是在请求js,css或者图片等静态文件时,用户的请求都会被重定向至index.php,下面咱们编写index.php
define('ROOT_PATH', str_replace('\', '/', dirname(__FILE__)));//定义根目录 /* 加载核心模块 */ require ROOT_PATH.'/config.php';//主要设置 require ROOT_PATH.'/core/Dispatcher.php';//分发器模块 $dpt = new Dispatcher();//实例化请求分发器 $return_status = $dpt->run(); echo $return_status; exit(0);
用户的请求在框架初始化完成后被传送到分发器中,分发器其实就是肯定对用户请求分发的依据,咱们能够根据URI分段来肯定控制器,例如用户请求 http://www.example.com/aaa/bbb,那么分发器就认为须要调用控制器aaa里面bbb方法来处理用户请求;还能够经过查询串 的方式,例如对于请求http://www.example.com?controller=aaa&method=bbb,分发器就知道须要调 用aaa控制器里面的bbb方法。在咱们的small-framework里,咱们采用URI分段的形式来对请求进行分发。分发器的代码以下:
class Dispatcher { private $path; public function __construct() { //实例化分发器时获得用户请求的URI $this->path = $_SERVER['PATH_INFO']; } public function run() { //分析URI,获得相应的控制器和方法 $this->path = trim($this->path, '/'); $paths = explode('/', $this->path); //获得控制器类名和方法名 $control = array_shift($paths); $method = array_shift($paths); //若是控制器类名和方法名为空,则默认为“index” if($control == '') $control = 'index'; if($method == '') $method= 'index'; //根据框架的文件结构,获得控制器类的文件路径 $control_file_name = ROOT_PATH.'/controller/'.$control.'.php'; if(file_exists($control_file_name)) { include_once($control_file_name); $controller_name = $control.'_Controller'; if(class_exists($controller_name)) { //实例化控制器 $control = new $controller_name(); if(method_exists($controller_name, $method)) { //若是用户请求的方法存在,则调用之 $control->$method(); return OK_200; } else return ERROR_404'; } else return ERROR_404; } else return ERROR_404; } };
分发器经过$contorl->$method()
调用了请求指定的控制器方法,如今咱们就能够试验一下,在controller/下面创建一个aaa.php,在里面声明一个名为aaa_Controller的类和名为bbb的访问权限为public的方法,就能够经过 [你的测试地址]/aaa/bbb
来访问这个控制器了。
如今咱们的small-framework实际上还不能被称做是一个框架,由于它尚未定义一些基本的操做,如调用数据模型、视图等,这些基本操做 咱们定义在core/下的Controller.php、Model.php、View.php里,用户自定义的控制器、模型和视图须要继承自这三个父 类。咱们须要在index.php中加载者三个父类。
在index.php中,除了加载核心模块之外,咱们还加载了用户本身写的Model、Controller和View须要继承的父类,在父类里面咱们须要定义一些框架的基本操做供用户调用
/* 加载Controller须要继承的父类 */ require ROOT_PATH.'/core/Controller.php'; /* 加载Model须要继承的父类 */ require ROOT_PATH.'/core/Model.php'; /* 加载View须要继承的父类 */ require ROOT_PATH.'/core/View.php';
首先是Controller.php,咱们默认在实例化Controller时就实例化View,用户在控制器中可直接使用View中的函数;固然也可让用户来手动载入View。代码以下
class Controller{ protected $view = NULL; protected $model = NULL; public function __construct() { //默认实例化Controller时就实例化View $this->view = new View(); } //用户经过model_name来手动载入相应的模型 protected function load_model($model_name) { $model_file_name = ROOT_PATH.'/model/'.$model_name.'.php'; require_once($model_file_name); $this->model = new $model_name(); } };
在View里咱们定义了show方法,show方法的参数是视图文件名和传给视图文件的数据,用户在控制器里能够调用show方法来输出指定的视图
class View{ public function show($view_file, $data=array()) { $view_file_name = ROOT_PATH.'/view/'.$view_file.'.php'; if(!file_exists($view_file_name)) return FALSE; //把数组展开,键名作变量名,键值作变量值 extract($data); //引入view文件 include($view_file_name); return TRUE; } };
在Model.php里面咱们能够封装一些数据库查询,在全部的查询以前对sql语句进行过滤,以保证数据库的安全
class Model{ //数据库链接 protected $link = NULL; public function __construct() { $this->link = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS); mysql_select_db(MYSQL_DB, $this->link); mysql_query("SET NAMES ".MYSQL_CHARSET); } /** 检查输入的sql语句,过滤敏感字符*/ private function _check($sql) { /*此处添加对$sql的过滤*/ return $sql; } /** 执行sql命令,成功返回结果集和TRUE,失败返回FALSE */ protected function query($sql) { return mysql_query($this->_check($sql)); } /** 执行sql查询,返回结果数组,查询失败返回false*/ protected function fetch_array($sql) { $res = $this->query($sql); return mysql_fetch_array($res); } /** 还能够添加其余的数据处理操做*/ };
到如今,咱们的small-framework的就基本完成了,small-frame的很简单,可是做为学习软件的mvc架构和php框架的入门 应该足够了,并且其余的大型PHP框架(这里的大型是相对于small-framework来讲的)的工做原理于small-framework也都是大 同小异的,大型框架中的分发器设置的会更加合理,还会有不少使用的类库供用户调用,有时间的话建议看看大型框架的源代码,学习其中的思想,大型框架里面还 有许多代码优化可供学习。