說到寫PHP的MVC框架,你們想到的第一個詞--「造輪子」,是的,一個尚未深厚功力的程序員,寫出的PHP框架確定不如那些出自大神們之手、通過時間和各類項目考驗的框架。但我仍是準備而且這麼作了,主要是由於:php
因此說,此次造輪子的目的不是爲了造輪子而是爲了在造輪子的過程當中熟悉其工藝,總結輪子特色,更好的使用輪子。html
若是說寫一個完整的PHP框架,那須要掌握的PHP知識點很是多,像設計模式、迭代器、事件與鉤子等等,還有許多基礎知識的靈活應用。我自認爲這些還沒法徹底掌控,因此個人步驟是先本身搭建一個骨架,而後參考借鑑不一樣的PHP框架的特色,將其慢慢完善。由於工做緣由,並且晚上還要補算法、網絡等編程基礎,PHP框架部分可能只有週末有時間更新,我會在進行框架功能更新以後,總結使用的知識點,更新博文。git
首先放上框架的目前源碼:GITHUB/zhenbianshu程序員
首先本身總結一下PHP的MVC框架的工做流程:github
簡單來講,它以一個入口文件來接受請求,選擇路由,處理請求,返回結果。web
固然,幾句話總結完的東西實際上要作的工做不少,PHP框架會在每次接受請求時,定義常量,加載配置文件、基礎類,根據訪問的URL進行邏輯判斷,選擇對應的(模塊)控制器和方法,而且自動加載對應類,處理完請求後,框架會選擇並渲染對應的模板文件,以html頁面的形式返回響應。在處理邏輯的時候,還要考慮到錯誤和異常的處理。算法
一、做爲MVC框架,必定要有一個惟一的入口文件來統領全局,全部的訪問請求都會首先進入這個入口文件,如我框架根目錄的index.php,在裏面,我定義了基本文件夾路徑,當前環境,並根據當前環境定義錯誤報告的級別。數據庫
二、PHP中加載另外的文件,使用require和include,它們都是將目標文件內容加載到當前文件內,替換掉require或include語句,require是加載進來就執行,而include是加載進來在須要的時候執行,而它們的_once結構都是表示在寫屢次的時候只執行一次。編程
三、框架內的配置變量等使用專用的配置文件來保存,這裏我仿照了TP裏的數組返回法,用了一個compileConf()函數來解析數組,將數組的鍵定義爲常量,值爲數組的值。bootstrap
if (!function_exists('compile_conf')) { function compileConf($conf) { foreach ($conf as $key => $val) { if(is_array($val)){ compileConf($val); }else{ define($key, $val); } } } } compileConf(require_once CONF_PATH.'config.php');
爲何把命名空間和自動加載放到一塊說呢?
在一個PHP項目中,類特別多的時候,若是類名重複的話就會形成混亂,並且相同文件夾內也不能存在同名的文件,因此這時候命名空間和文件夾就搭檔出場了。文件夾就是一個一個的盒子,命名空間在我理解就像是一個標籤,盒子對應標籤。咱們定義類時,把各類類用不一樣的盒子分別裝好,並貼上對應的標籤。而在自動加載類時,咱們根據標籤(命名空間)能夠很輕易找到對應的盒子(文件夾)而後找到對應的類文件。
而類的自動加載,咱們知道的__autoload()魔術函數,它會在你實例化一個當前路徑找不到的對象時自動調用,根據傳入的類名,在函數體內加載對應的類文件。
如今咱們多用spl_autoload_register()函數,它能夠註冊多個函數來代替__autoload函數的功能,咱們傳入一個函數名爲參數,spl_autoload_register會將這個函數壓入棧中,在實例化一個當前路徑內找不到的類時,系統將會將函數出棧依次調用,直到實例化成功。
spl_autoload_register('Sqier\Loader::autoLoad'); class Loader { public static function autoLoad($class) { //若是有的話,去除類最左側的\ $class = ltrim($class, '\\'); //獲取類的路徑全名 $class_path = str_replace('\\', '/', $class) . EXT; if (file_exists(SYS_PATH . $class_path)) { include SYS_PATH . $class_path; return; } if (file_exists(APP_PATH . $class_path)) { include APP_PATH . $class_path; return; } }
如今Loader類仍是一個簡單的類,待之後慢慢完善。
接下來就是路由選擇了,其本質是根據當前定義的全局URL模式選擇合適的方法來分析傳入的URI,加載對應的類,並實現對應的方法。
class Router { public static $uri; public static function bootstrap() { self::$uri = $_SERVER['REQUEST_URI']; switch (URL_MODE) { case 1: { self::rBoot(); break; } default: { self::rBoot(); } } } public static function rBoot() { $router = isset($_GET['r']) ? explode('/', $_GET['r']) : [ 'index', 'index' ]; $cName = 'Controller\\' . ucfirst($router[0]); $aName = isset($router[1]) ? strtolower($router[1]) . 'Action' : 'indexAction'; $controller = new $cName(); $controller->$aName(); } }
這樣,我在地址欄輸入 zbs.com/index.php?r=index/login 後,系統會自動調用/app/Controller/Index.php下的login方法。完成了這麼一個簡單的路由。
接下來我會優化現有的工具類,添加顯示層,添加數據庫類,還會將一些別的框架裏很是cool的功能移植進來~
待續...