1. 程式人生 > >1小時內打造你自己的PHP MVC框架

1小時內打造你自己的PHP MVC框架

簡介

MVC框架在現在的開發中相當流行,不論你使用的是JAVA,C#,PHP或者IOS,你肯定都會選擇一款框架。雖然不能保證100%的開發語言都會使用框架,但是在PHP社群當中擁有最多數量的MVC框架。今天你或許還在使用Zend,明天你換了另一個專案也許就會轉投Yii,Laravel或者CakePHP的懷抱。如果你剛開始使用一種框架,當你看它的原始碼的時候你會覺得一頭霧水,是的,這些框架都很複雜。因為這些流行的框架並不是短時間之內就寫出來就發行的,它們都是經過一遍又一遍的編寫和測試加上不斷的更新函式庫才有了今天得模樣。所以就我的經驗來看,瞭解MVC框架的設計核心理念是很有必要的,不然你就會感覺在每一次使用一個新的框架的時候一遍又一遍的從頭學習。

所以最好的理解MVC的方法就是寫一個你自己的MVC框架。在這篇文章中,我將會向你展示如何構建一個自己的MVC框架

MVC架構模式

M: Model-模型

V: View-檢視

C: Controller-控制器

MVC的關鍵概念就是從檢視層分發業務邏輯。首先解釋以下HTTP的請求和相應是如何工作的。例如,我們有一個商城網站,然後我們想要新增一個商品,那麼最簡單的一個URL就會是像下面這個樣子:

p=admin 意味著處在管理模組,,或者是系統的後臺模組。同時我們肯定也擁有前臺模組,前臺模組供所有使用者訪問(本例中, 它是p=public)


c=goods&a=add 意思是URL請求的是goods控制器裡的add方法。

前臺控制器設計

在上面的例子中index.php中是什麼?在PHP框架中它被稱為入口檔案。這個檔案通常都被命名為index.php,當然你也可以給它別的命名。這個index.php的最主要的作用就是作為HTTP請求的唯一入口檔案,這樣無論你的URL請求什麼資源,它都必須通過這個Index.php來請求。你可能要問為什麼,它是如何做到的?PHP中的前端控制器用到了Apache伺服器的分散式配置.htaccess實現的。在這個檔案中,我們可以使用重寫模組告訴Apache伺服器重定向到我們的index.php入口檔案,就像下面這樣:

<IfModule mod_rewrite.c>

   

   Options +FollowSymLinks

   RewriteEngine on


   # Send request via index.php

   RewriteCond %{REQUEST_FILENAME} !-f

   RewriteCond %{REQUEST_FILENAME} !-d

   RewriteRule ^(.*)$ index.php/$1 [L]


</IfModule>

這個配置檔案非常有用,還有當你重寫這個配置檔案的時候你不需要重啟Apache。但是當你修改Apache的其他配置檔案的時候你都需要重啟Apache才能生效,因為Apache只有在啟動的時候才會讀取這些配置檔案。

同時,index.php還會進行框架的初始化並且分發路由請求給對應的控制器和方法。

我們的MVC目錄結構

現在讓我們開始建立我們的框架目錄結構。我們你可以隨便先建立一個資料夾,命名為你專案的名稱,比如:/bestshop。在這個資料夾下你需要建立下面的資料夾:

/application-存放web應用程式目錄

/framework-存放框架檔案目錄

/public-存放所有的公共的靜態資源,比如HTML檔案,CSS檔案和jJS檔案。

index.php-唯一入口檔案

然後在application資料夾下再建立下一級的目錄

/config-存放應用的配置檔案

/controllers-應用的控制器類

/model-應用的模型類

/view-應用的檢視檔案

 

現在在application/controllers資料夾下,我們還需要建立兩個資料夾,一個frontend,一個backend:

同樣的,在view下也建立frontend和backend資料夾:

就像你看到的,在application的controllers和view下面建立了backen和frontend資料夾,就像我們的用用有前臺和後臺功能一樣。但是為什麼不在model下也這樣做呢?

Well, the reason here is, normally for a web app:是因為一般在我們的應用中,前臺和後臺其實是可以看做是兩個“網站的”,但是CRUD操作的是同一個資料庫,這就是問什麼管理員更新了貨物的價格的時候,前臺使用者可以馬上看到價格的變化,因為前臺和後臺是共享一個數據庫(表)的。所以在model中沒必要再去建立兩個資料夾。

:現在讓我們回到framework資料夾中,一些框架的資料夾命名會用框架的名字命名,比如"symfony"。在framework中讓我們快速建立下面的子目錄:

/core-框架核心檔案目錄

/database-資料庫目錄(比如資料庫啟動類)

/helpers-輔助函式目錄

/libraries-類庫目錄

現在進入public資料夾,建立下面的目錄:

/css-存放css檔案

/images-存放圖片檔案

/js-存放js檔案

/uploads-存放上傳的檔案

OK。到目前為止這就是我們這個迷你的MVC框架的目錄結構了!

框架核心類

現在在framework/core下建立一個Framework.class.php的檔案。寫入以下程式碼:

// framework/core/Framework.class.php

class Framework {


   public static function run() {

       echo "run()";

   }

我們建立了一個靜態方法run(),現在讓我們通過入口檔案index.php測試一下:

<?php


require "framework/core/Framework.class.php";


Framework::run();

你可以在你的瀏覽器裡訪問index.php看到結果。通常這個靜態方法被命名為run()或者bootstrap()。在這個方法中,我們要做3件最主要的事情:

class Framework {


   public static function run() {

//        echo "run()";

       self::init();

       self::autoload();

       self::dispatch();

   }


   private static function init() {

   }


   private static function autoload() {


   }


   private static function dispatch() {


   }

}

初始化

init()方法:

// Initialization

private static function init() {

    // Define path constants

    define("DS", DIRECTORY_SEPARATOR);

    define("ROOT", getcwd() . DS);

    define("APP_PATH", ROOT . 'application' . DS);

    define("FRAMEWORK_PATH", ROOT . "framework" . DS);

    define("PUBLIC_PATH", ROOT . "public" . DS);


    define("CONFIG_PATH", APP_PATH . "config" . DS);

    define("CONTROLLER_PATH", APP_PATH . "controllers" . DS);

    define("MODEL_PATH", APP_PATH . "models" . DS);

    define("VIEW_PATH", APP_PATH . "views" . DS);


    define("CORE_PATH", FRAMEWORK_PATH . "core" . DS);

    define('DB_PATH', FRAMEWORK_PATH . "database" . DS);

    define("LIB_PATH", FRAMEWORK_PATH . "libraries" . DS);

    define("HELPER_PATH", FRAMEWORK_PATH . "helpers" . DS);

    define("UPLOAD_PATH", PUBLIC_PATH . "uploads" . DS);


    // Define platform, controller, action, for example:

    // index.php?p=admin&c=Goods&a=add

    define("PLATFORM", isset($_REQUEST['p']) ? $_REQUEST['p'] : 'home');

    define("CONTROLLER", isset($_REQUEST['c']) ? $_REQUEST['c'] : 'Index');

    define("ACTION", isset($_REQUEST['a']) ? $_REQUEST['a'] : 'index');


    define("CURR_CONTROLLER_PATH", CONTROLLER_PATH . PLATFORM . DS);

    define("CURR_VIEW_PATH", VIEW_PATH . PLATFORM . DS);


    // Load core classes

    require CORE_PATH . "Controller.class.php";

    require CORE_PATH . "Loader.class.php";

    require DB_PATH . "Mysql.class.php";

    require CORE_PATH . "Model.class.php";


    // Load configuration file

    $GLOBALS['config'] = include CONFIG_PATH . "config.php";


    // Start session

    session_start();

}

在註釋中你可以看到每一步的目的。

自動載入

在專案中,我們不想在指令碼中想使用一個類的時候手動的去include或者require載入,這就是為什麼PHP MVC框架都有自動載入的功能。例如,在symfony中,如果你想要載入lib下的類,它將會被自動引入。很神奇是吧?現在讓我們在自己的框架中加入自動載入的功能。

這裡我們要用的PHP中的自帶函式spl_autoload_register:

// Autoloading

private static function autoload(){

    spl_autoload_register(array(__CLASS__,'load'));

}


// Define a custom load method

private static function load($classname){


    // Here simply autoload app&rsquo;s controller and model classes

    if (substr($classname, -10) == "Controller"){

        // Controller

        require_once CURR_CONTROLLER_PATH . "$classname.class.php";

    } elseif (substr($classname, -5) == "Model"){

        // Model

        require_once  MODEL_PATH . "$classname.class.php";

    }

}

每一個框架都有自己的命名規則,我們的也不例外。對於一個控制器類,它需要被命名成類似xxxController.class.php,對於一個模型類,需要被命名成xxModel.class.php。為什麼在使用一個框架的時候你需要遵守它的命名規則呢?自動載入就是一條原因。

路由/分發

// Routing and dispatching

private static function dispatch(){

    // Instantiate the controller class and call its action method

    $controller_name = CONTROLLER . "Controller";

    $action_name = ACTION . "Action";

    $controller = new $controller_name;

    $controller->$action_name();

}

在這步中,index.php將會分發請求到對應的Controller::Aciton()方法中。

基礎Controller類

通常在框架的核心類中都有一個基礎的控制器。在symfony中,被稱為sfAction;在iOS中,被稱為UIViewController。在這裡我們命名為Controller,在framework/core下建立Controller.class.php

<?php

// Base Controller

class Controller{

    // Base Controller has a property called $loader, it is an instance of Loader class(introduced later)

    protected $loader;


    public function __construct(){

        $this->loader = new Loader();

    }


    public function redirect($url,$message,$wait = 0){

        if ($wait == 0){

            header("Location:$url");

        } else {

            include CURR_VIEW_PATH . "message.html";

        }


        exit;

    }

}

基礎控制器有一個變數$loader,它是Loader類的例項化(後面介紹)。準確的說,$this->loader是一個變數指向了被例項化的Load類。在這裡我不過多的討論,但是這的確是一個非常關鍵的概念。我遇到過一些PHP開發者相信在這個語句之後:

$this->loader = new Loader();

$this->load是一個物件。不,它只是一個引用。這是從Java中開始使用的,在Java之前,在C++和Objective C中被稱為指標。引用是個封裝的指標型別。比如,在iOS(O-C)中,我們建立了一個物件:

UIButton *btn = [UIButton alloc] init];

載入類

在framework.class.php中,我們已經封裝好了應用的控制器和模型的自動載入。但是如何自動載入在framework目錄中的類呢?現在我們可以新建一個Loader類,它會載入framework目錄中的類和函式。當我們載入framework類時,只需要呼叫這個Loader類中的方法即可。

class Loader{

    // Load library classes

    public function library($lib){

        include LIB_PATH . "$lib.class.php";

    }


    // loader helper functions. Naming conversion is xxx_helper.php;

    public function helper($helper){

        include HELPER_PATH . "{$helper}_helper.php";

    }

}

封裝模型

我們需要下面兩個類來封裝基礎Model類:

Mysql.class.php - 在framework/database下建立,它封裝了資料庫的連結和一些基本查詢方法。

Model.class.php - framework/core下建立,基礎模型類,封裝所有的CRUD方法。

Mysql.class.php :

<?php

/**

*================================================================

*framework/database/Mysql.class.php

*Database operation class

*================================================================

*/

class Mysql{

    protected $conn = false;  //DB connection resources

    protected $sql;           //sql statement

   

    /**

     * Constructor, to connect to database, select database and set charset

     * @param $config string configuration array

     */

    public function __construct($config = array()){

        $host = isset($config['host'])? $config['
            
           

相關推薦

1小時打造自己PHP MVC框架

簡介 MVC框架在現在的開發中相當流行,不論你使用的是JAVA,C#,PHP或者IOS,你肯定都會選擇一款框架。雖然不能保證100%的開發語言都會使用框架,但是在PHP社群當中擁有最多數量的MVC框架。今天你或許還在使用Zend,明天你換了另一個專案也許就會轉投

mvc原理:打造自己MVC框架1.0

一、MVC的原理 從請求到服務端接受到請求中間這個過程經歷了哪些步驟: 第一步:請求被UrlRoutingModule部件攔截 第二步:封裝請求上下文HttpContext,成為HttpContextWrapper 第三步:根據當前的HttpContext,從Routes集合中得到與

PHP搭建自己MVC框架 1

在PHP中使用MVC越來越流行了,特別是在一些開源的框架當中。MVC足以應對大多數的情況,但還有一些情況是其不太適合的,如比較簡單的個人部落格,對於只有幾百篇文章量級的部落格,使用MVC讓人覺得有些太複雜了;同樣對於新浪等入口網站,使用MVC,將有大量的檔案被載入,對於速度

自己動手寫PHP-MVC框架(一)

自己動手模仿寫一個php的框架,首先是要明白原理,然後寫的話思路就比較清晰。 當前應用的基本組成是有一堆的資料夾和一個index的檔案組成         |-Conf       &n

編寫自己PHP MVC框架

1 什麼是MVC MVC模式(Model-View-Controller)是軟體工程中的一種軟體架構模式。 MVC把軟體系統分為三個基本部分:模型(Model)、檢視(View)和控制器(Controller)。 PHP中MVC模式也稱Web MVC,從上世紀7

MVC系列——MVC原始碼學習:打造自己MVC框架(四:瞭解神奇的檢視引擎)

前言:通過之前的三篇介紹,我們基本上完成了從請求發出到路由匹配、再到控制器的啟用,再到Action的執行這些個過程。今天還是趁熱打鐵,將我們的View也來完善下,也讓整個系列相對完整,博主不希望爛尾。對於這個系列,通過學習原始碼,博主也學到了很多東西,在此還是把博主知道的先發出來,供大家參考。 MVC原

MVC系列——MVC原始碼學習:打造自己MVC框架(一:核心原理)

前言:最近一段時間在學習MVC原始碼,說實話,研讀原始碼真是一個痛苦的過程,好多晦澀的語法搞得人暈暈乎乎。這兩天算是理解了一小部分,這裡先記錄下來,也給需要的園友一個參考,奈何博主技術有限,如有理解不妥之處,還希望大家斧正,博主感激不盡! MVC原始碼學習系列文章目錄: 一、MVC原理解析  最

MVC系列——MVC原始碼學習:打造自己MVC框架(二:附原始碼)

前言:上篇介紹了下 MVC5 的核心原理,整篇文章比較偏理論,所以相對比較枯燥。今天就來根據上篇的理論一步一步進行實踐,通過自己寫的一個簡易MVC框架逐步理解,相信通過這一篇的實踐,你會對MVC有一個更加清晰的認識。 MVC原始碼學習系列文章目錄: 這篇博主打算從零開始一步一步來加上MVC裡面用到

MVC系列——MVC原始碼學習:打造自己MVC框架(三:自定義路由規則)

前言:上篇介紹了下自己的MVC框架前兩個版本,經過兩天的整理,版本三基本已經完成,今天還是發出來供大家參考和學習。雖然微軟的Routing功能已經非常強大,完全沒有必要再“重複造輪子”了,但博主還是覺得自己動手寫一遍印象要深刻許多,希望想深入學習MVC的童鞋自己動手寫寫。好了,廢話就此打住。 MVC原始

做一個自己MVC框架[php]

外包的活幹多了,總有一些小專案,這些小專案甚至不需要考慮安全。這時候用框架顯得浪費。自己手寫原生程式碼又有些不太習慣(框架用多了,有時候連基本的都忘了,不能忘本啊。。。) 許久不更的部落格。反正也沒多少人看,哈~就當給自己一個馬克,也希望能給一些剛踏入程式猿大

使用PHP搭建自己MVC框架

模型(Model) “資料模型”(Model)用於封裝與應用程式的業務邏輯相關的資料以及對資料的處理方法。“模型”有對資料直接訪問的權力,例如對資料庫的訪問。“模型”不依賴“檢視”和“控制器”,也就是說,模型不關心它會被如何顯示或是如何被操作。但是模型中資料的變化一般會通過一種重新整理機制被公佈。為了實現

每個程式設計師1小時必須解決的5個程式設計問題之難題

昨天看到一篇文章說,軟體開發人員應一小時完成的5道題,其中第5道題,還是比較難的。看了一下作者的原來解題思路,就是採用治減法,這是一類問題的演算法題,如果沒有接觸過,確實有點難度。作者提供了JAVA的原

打造自己的圓形或圓環形progressBar——圓形SeekBar演變圓形progressbar

簡介 上篇部落格給大家分析了圓形SeekBar的案例,不瞭解的朋友請看上篇文章。這裡在圓形SeekBar的基礎上給大家演變出圓形的progressBar和圓環形的ProgressBar。先看效果圖:   分析 上篇文章分析了圓環seekBar的實現,那如何將Se

神箭手雲爬蟲平臺 如何在1小時編寫簡單爬蟲

既然你來到了這裡,想必你肯定已經知道了神箭手雲爬蟲平臺是幹什麼的,目的也是非常的明確。 那麼接下來的過程中,我將給你演示如何在最快時間內編寫一個簡單的爬蟲,每一個屬性的講解,將會讓你一路順風。 進入爬蟲市場 首先進入爬蟲市場,登入,

PHP MVC框架基礎小白(自己動手寫一個PHP框架示例)

一個示例專案,具體展示了PHP,MVC模式框架開發的全過程本人小白一個,希望各位大神多多指教,由於教程文字過多而且不易解釋我直接將示例專案打包,下面附上鍊接各位對PHP框架學習可以借鑑專案內帶有其他方法和註釋,希望能對大家有所幫助

PHP搭建自己MVC框架8 檢視層

接下來實現檢視層 檢視層包括變數賦值(assign) 和 呼叫模板(display) 控制器繼承基類 <?php namespace app\ctrl; class indexCtrl extends \core\mymvc { public functio

屬於自己的自動化框架思路

基礎 學什麽 梳理 程序員 一個 維護 das selenium 去百度 前言 說起自動化,最先想到的應該就是一些編碼技術了。 比如至少會一種語言:java、python、js、c++、vb、等等; 用來設計測試用例和腳本框架,比如至少熟悉一種框架或工具:

JavaWeb之搭建自己MVC框架

. 介紹         MVC全名是Model View Controller,是模型(model)-檢視(view)-控制器(controller)的縮寫,一種軟體設計典範,用一種業務邏輯、資料、介面顯示分離的方法組織程式碼,將業務邏輯聚集到一個部件裡面,在改進和個性化

打造自己php的開發框架--phpMVC簡單實現

從本篇開始介紹如何用php來實現MVC模式開發,而且後續的文章也是在這個基礎上不斷改造優化。關於MVC這裡就不多說了,並且在以後的文章裡也是以講技術為主。     本篇先介紹一下php的MVC實現原理,我們框架的MVC部分也是基於此原理實現的,但是今天的程式碼並不是框架