開發框架的定義我沒有找到很準確的描述,下面幾句話基本歸納了開發框架的的功能和用途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也都是大 同小異的,大型框架中的分發器設置的會更加合理,還會有不少使用的類庫供用戶調用,有時間的話建議看看大型框架的源代碼,學習其中的思想,大型框架裏面還 有許多代碼優化可供學習。