(轉)PHP開發框架淺析


開發框架的定義我沒有找到很准確的描述,下面幾句話基本概括了開發框架的的功能和用途

  • 框架是一種應用程序的半成品;
  • 框架就像是人的骨骼一樣;
  • 框架是一組可復用的組件;
  • 框架是一個可復用的設計構件……

簡而言之,框架就是制定一套規范或者規則(思想),大家(程序員)在該規范或者規則(思想)下工作。或者說就是使用別人搭好的舞台,你來做表演。

PHP開發框架有哪些優缺點

優點:上面說過,框架其實就是別人把一些基礎的代碼給封裝成庫,讓程序員來調用,例如表單驗證、文件上傳、驗證 碼之類的基礎功能;框架還把程序的設計架構給確定了,所以程序員只需按照框架規定的方法來寫上自己的核心代碼,程序就能基本成型了。所以應用PHP開發框 架可以使程序員只需專注於應用的核心代碼,基礎代碼可直接調用框架的類庫,而且框架的設計架構可以保證團隊開發時代碼的一致性,所以可以大大提高WEB應 用開發的效率。

缺點:這世界什么東西都不是完美的,所以利用框件架開發有利也有弊。PHP框架缺點就是過分封裝了PHP的基礎 函數,對與一個PHP新手來說,他可能不需要學習PHP的任何基礎函數,僅靠翻閱框架的說明文檔和調用框架封裝好的接口就能完成一個完整的PHP應用程 序,從某方面說這樣可以降低PHP應用開發的技術要求,但是這樣對於學習來說是不利的,最后會導致過於依賴開發框架。在一個論壇里看到這樣一句話評論 PHP開發框架:

學之者生,用之者死

MVC架構

什么是MVC架構

MVC是軟件工程中的一種軟件架構模式,MVC把軟件系統分成三個基本部分:模型(Model)、視圖(View)和控制器(Controller)。

模型(Model)“數據模型”(Model)用於封裝與應用程序的業務邏輯相關的數據以及對數據的處理方法。 “模型”有對數據直接訪問的權力,例如對數據庫的訪問。“模型”不依賴“視圖”和“控制器”,也就是說,模型不關心它會被如何顯示或是如何被操作。但是模 型中數據的變化一般會通過一種刷新機制被公布。為了實現這種機制,那些用於監視此模型的視圖必須事先在此模型上注冊,從而,視圖可以了解在數據模型上發生 的改變。

視圖(View) 視圖層能夠實現數據有目的的顯示(理論上,這不是必需的)。在視圖中一般沒有程序上的邏輯。為了實現視圖上的刷新功能,視圖需要訪問它監視的數據模型(Model),因此應該事先在被它監視的數據那里注冊。

控制器(Controller) 控制器起到不同層面間的組織作用,用於控制應用程序的流程。它處理事件並作出響應。“事件”包括用戶的行為和數據模型上的改變。

mvc

MVC架構在WEB開發中的應用

MVC在WEB應用程序中應用較廣泛,右圖是一個基於MVC的WEB請求處理過程。

首先,用戶發送一個請求給控制器(Controller),控制器根據用戶的請求向數據模型(Model)發送數據需求,數據模型根據需求進行相應 的數據處理(如訪問數據庫、進行相應的計算等)后,把數據結果傳回控制器,控制器得到數據后,就可以調用視圖(View),生成一個頁面,返回給用戶。

開發一個簡單的PHP框架

上面說了那么多,下面我們動手開發一個簡單的PHP框架程序,框架聽起來好像挺復雜的,其實還是很簡單的,只要弄懂了它的思想就沒有問題。我們框架的名字就叫small-framework吧。

粗略的分析用戶請求的處理過程

我們知道PHP每次接收到請求時都要初始化全部資源,處理完畢后再釋放全部的資源,PHP框架也是如此。框架接收到用戶的請求后,需要一個初始化的 過程,在初始化時實例化框架的核心模塊,然后在把請求傳送給框架的相應模塊進行處理。因為不可能所有的請求都使用同一個控制器,除非程序功能非常簡單,所 以在初始化完成后,我們還需要根據用戶的請求來調用相應的控制器,所以我們需要一個分發器(Dispatcher)來對用戶的請求進行分發。在控制器里, 我們就可以調用數據模型和視圖來處理用戶的請求了。

mvc-1

細致的分析用戶請求的處理過程

上面粗略的分析了用戶請求的處理流程,下面進行更加精細的分析

從上面的分析可以知道,要處理用戶的請求需要先初始化框架的核心模塊,如分發器模塊,所以用戶的請求首先需要被重定向至一個初始化頁面,重定向可以 使用.htaccess文件來實現,在我們這個框架里,我們首先把所有的請求都重定向至index.php里,在index.php里面完成初始化操作: 初始化核心模塊,我們還可以在初始化時讀入框架的配置文件信息,然后調用分發器把請求分發到相應的控制器,實例化這個控制器,並調用控制器中的方法來處理 用戶的請求。在控制器里,我們可以獲取用戶的輸入,判斷用戶的請求,然后調用相應的數據模型進行數據處理,控制器得到數據后,把數據傳給視圖,視圖根據得 到的數據返回一個頁面給用戶,請求結束。

mvc-2

框架的文件結構

根據上面的分析,我們可以列出small-framework的文件結構

  • Core/                    框架的核心模塊

  • Dispatcher.php

  • Controller.php
  • Model.php
  • View.php

  • Controller/          自定義的控制器

  • View/                   自定義的視圖
  • Model/                自定義的數據模型
  • index.php           框架的單一入口
  • config.php          框架的配置文件
  • .htaccess             將請求重定向至index.php

開始編碼

有了以上的分析,框架工作的基本流程我們基本清楚了,下面我們就按照請求的處理順序來開始編碼

首先是.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也都是大 同小異的,大型框架中的分發器設置的會更加合理,還會有很多使用的類庫供用戶調用,有時間的話建議看看大型框架的源代碼,學習其中的思想,大型框架里面還 有許多代碼優化可供學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM