本教程翻譯自John Squibb 的Build a PHP MVC Framework in an Hour,但有所改動,原文地址:http://johnsquibb.com/tutorialsphp
這個教程可使你們掌握用mvc模式開發php應用的基本概念。此教程分爲三個部分,如今這篇是第一部分。html
如今市面上有不少流行的框架供你們使用,可是咱們也能夠本身動手開發一個mvc框架,採用mvc模式能夠大大減小咱們開發應用的時間,而且可以更好的組織項目源代碼,並且其中的某些模塊還可在其它項目中使用。如今我要教你們寫一個簡單的mvc框架。因爲這個項目很簡單,輕量,因此可能並非最佳實踐,也不具有安全性,還須要你們在實際應用中完善。前端
所用技術:php,面向對象開發方法。web
開始數據庫
首先在網站根目錄下創建三個文件夾編程
而後在根目錄下新建一個文件:數組
如今項目結構應該像這樣瀏覽器
§ 網站根目錄安全
§ 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');
- ?>
若是順利的話,你能夠打開瀏覽器輸入:
- http://你的域名.com/index.php?news&article=howtobuildaframework
咱們會看到以下輸出
- The page you requested is 'news'
- The following GET vars were passed to the page:
-
- Array
- (
- [article] => howtobuildaframework
- )
-
若是沒有上述輸出,請檢查你的服務器配置是否正確,並檢查代碼是否有錯誤。
如今來讓咱們添加一個頁面到咱們的網站裏,這樣就可讓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,再刷新一次瀏覽器,你會看到: