最新在你們本身的博客的過程當中,發現各類開源的博客系統都或多或少的用起來彆扭.因而想動手本身寫個博客系統.既然寫,就想好好寫.那就先寫個MVC框架.一點一點來.寫的過程當中有不少想法.還但願你們可以多多指正.我在這裏先把它們記錄下來.下面是我對這個系統的一些想法.php
1,我要實現一個模塊話的博客系統,可以進行二次開發.mysql
2,我要實現apache和nginx的rewrite功能.nginx
3,我要實現對多數據庫的支持.包括mongodb和mysql 還有mysqli.等.sql
4,我要把smarty用起來.mongodb
好,下面動手開始寫.首先一點我得設計一下這個系統.大概的目錄結構是下面這個樣子的(我參考了PHPCMS).數據庫
/apache
./log--這個是日誌目錄.我想把日誌記錄在這個裏面數組
./system ---這個是系統目錄mvc
./lib--這個是系統庫.關鍵的東西都放在這裏面框架
./classes -- 這個是系統的相關類
./configs--這個是系統的配置文件目錄
./model--這個是各個數據模型的目錄
./modules--這個是各個模塊的目錄
./base.php--全部的請求都路由到這個文件上面來了,再有這個文件來分發.
./index --我把index也當成一個模塊來寫
./templates--這個是模板目錄
./default--這個是默認的模板目錄
./cache--這個是cache目錄.
index.php-----------這個是單入口文件,用來路由相關的請求.
MVC框架要把model和ctrl還有view分開.那麼就須要url的路由.至於僞靜態什麼的,後面再說.要先知足最基本的需求.
MVC框架要有個單入口文件,因而第一個文件產生了.就是根目錄下面的index.php,這個文件用來接收全部的請求,也就是說全部的請求都是從這個入口進來的.關於單入口的好處,請自行搜索腦補.
每個數據模型,按照個人理解,應該對應一張或者多張表.好比文章模型.能夠單獨對文章表.也能夠對應做者表and文章表and評論表.
涉及到數據模型就要與數據庫打交道了.先無論跟數據庫打交道.我最早要實現的是可以路由個人URL
最簡單的url http://域名.com要路由到index模塊下的index.php文件裏面的index控制器而且執行這個控制器的默認方法(我設置成了init);
既然要有默認的路由參數,我就創建了一個文件.叫default_arg.config.php 存放在/system/lib/configs/default_arg.config.php裏面用來返回默認的參數
裏面的內容大概是介個樣子滴:
<?php return array( 'default' => array( 'm'=>'index', 'c'=>'index', 'a'=>'init', ), );
當我想引用這些配置的時候 .我只須要以下的調用
$configs = include_once($file);
就可以將這個大數組賦值到configs上面,若是沒有參數,就使用默認的參數.把默認參數拼接到URL上面.個人默認首頁就變成了
http://域名.com/index.php?m=index&c=index&a=init
這一切的功能是怎麼實現的哦?
既然訪問的是index.php,那就從index.php開始看,其實index裏面就幾行,
define('ROOT_PATH',dirname(__FILE__));//定義一個系統路徑 require_once(ROOT_PATH.DIRECTORY_SEPARATOR.'system'.DIRECTORY_SEPARATOR.'base.php');//引用框架的基礎類 $sys = base::getInstance();//獲得基礎類的實例,基礎類是一個單例類 $sys->init();//調用單例類的init方法
其實DIRECTORY_SEPARATOR就是個/,咱們能夠這樣理解.引用了框架裏面的base文件.而後調用了裏面的getInstance方法.獲得了一個實力,最後調用了init方法.
爲何要使用單例類,能夠自行百度.這裏用單例類比較科學.後面我會把整個類貼上來,下面用到什麼就貼什麼.
再看看base類裏面的getInstance幹了些什麼.
class base{ public static $sys; private function __construct(){ return false; } public static function getInstance(){ if(!(self::$sys instanceof self)){ self::$sys = new self(); } return self::$sys; }
由於是單例類,我把base裏面的構造方法聲明成了私有的.這是爲了防止被new關鍵字從外部new這個類.爲了保證全部操做都是由單一實例來完成的.這個類是不容許在外部new的.
在看看getInstance方法.先判斷本身的$sys變量是否是本身的實例.若是不是就將本身的實例賦值給$sys,若是是則不作操做,最後 返回了這個類本身的一個實例.
在看看init方法作了些什麼
public static function init(){ self::sys_class('model'); self::sys_class('ctrl'); $args = self::__explan_arg(); $ctrl = self::__load_ctrl($args['m'],$args['c']); call_user_func(array($ctrl,$args['a'])); }
我在這個基礎類裏面寫了幾個方法.若是方法名稱前面有兩個下劃線,就是私有的方法. 有個sys_class就是在指定目錄加載系統了.這個目錄是/system/lib/class/. 這裏加載了model類和ctrl類,就是模型類的基類和控制器類的基類.這個ctrl類是全部控制器的基類.裏面能夠寫一些公共的方法.好比說在構造方法讓類中有一個base的實例神馬的.讓全部的控制器都集成自這個類.這個model類目前還沒用到.可是之後的數據模型都應該是來自這個model類的.後面會說.
而後我調用了__explan_arg方法.這個方法就是來解析get獲得的參數的.
private static function __explan_arg(){ $default_arg = self::sys_config('default_arg'); $args['m'] = isset($_GET['m'])?$_GET['m']:$default_arg['m']; $args['c'] = isset($_GET['c'])?$_GET['c']:$default_arg['c']; $args['a'] = isset($_GET['a'])?$_GET['a']:$default_arg['a']; return $args; }
我在第一行使用了一個sys_config方法來加載默認參數.這個方法就是在系統的/system/lib/configs/目錄下面找到對應的配置文件,上面已經說過了怎麼把數組返回.這樣當GET裏面沒有相應的參數的時候就會使用默認的參數.接下來咱們調用了__load_ctrl方法加載了相應的控制器.傳入了m和c.這個方法實現的就是到m所指定的目錄下面找到c這個文件而且實例化一個c這個類(也就是相應的控制器類.)而且返回相應控制器類的實例.而後我調用了一個call_user_func方法.由於咱們沒辦法在程序裏像下面的樣子來調用控制器的方法
$ctrl->$args['a'];//這樣是沒辦法調用的
因此咱們使用了call_user_func方法來調用相應控制器的方法.
好了,如今再縷縷咱們程序的流程.首先訪問了index.php-->index.php定義了一個路徑,去引用了base類.而且獲得了一個base類的實例.還調用了base的init方法.-->base的init方法作了下面的事情-->先去引用了基類model和ctrl-->去解析了url中的參數,獲得了m,c,a-->經過m,c來引用相應的控制器,-->調用相應控制器的a方法.而後就會獲得相應的輸出了.
到此爲止咱們的框架控制器部分基本算是完成了,默認的args是index,index,init.咱們在/modules/index/裏面創建一個index.php文件.裏面寫以下的內容.
<?php class c_index extends ctrl{ public function __construct(){ parent::__construct(); } public function init(){ echo "hello my mvc!"; } }
再來訪問咱們的根域名,那麼咱們就會獲得hello my mvc.這句話的輸出.
----------------------------------------------------------------------------------------------------------------------------------
畢竟是本身我的的思路.若是有什麼不妥的地方,歡迎你們拍磚,也但願你們可以一塊兒來參與討論,最近看到php的相關板塊不像之前那麼火了.還但願你們可以多多來參與發帖和討論.