<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    風(fēng)人園

    弱水三千,只取一瓢,便能解渴;佛法無邊,奉行一法,便能得益。
    隨筆 - 99, 文章 - 181, 評論 - 56, 引用 - 0
    數(shù)據(jù)加載中……

    MVC模式的PHP實(shí)現(xiàn)(zt)

    MVC模式在網(wǎng)站架構(gòu)中十分常見。它允許我們建立一個(gè)三層結(jié)構(gòu)的應(yīng)用程式,從代碼中分離出有用的層,幫助設(shè)計(jì)師和開發(fā)者協(xié)同工作以及提高我們維護(hù)和擴(kuò)展既有程式的能力。

    視圖(View)

    “視圖”主要指我們送到Web瀏覽器的最終結(jié)果??比如我們的腳本生成的HTML。當(dāng)說到視圖時(shí),很多人想到的是模版,但是把模板方案叫做視圖的正確性是值得懷疑的。

    對視圖來說,最重要的事情可能是它應(yīng)該是“自我意識(self aware)”的,視圖被渲染(render)時(shí),視圖的元素能意識到自己在更大框架中的角色。

    以XML為例,可以說XML在被解析時(shí),DOM API有著這樣的認(rèn)知??一個(gè)DOM樹里的節(jié)點(diǎn)知道它在哪里和它包含了什么。 (當(dāng)一個(gè)XML文檔中的節(jié)點(diǎn)用SAX解析時(shí)只有當(dāng)解析到該節(jié)點(diǎn)時(shí)它才有意義。)

    絕大多數(shù)模板方案使用簡單的過程語言和這樣的模板標(biāo)簽:

    <p>{some_text}</p>
    <p>{some_more_text}</p>


    它們在文檔中沒有意義,它們代表的意義只是PHP將用其他的東西來替換它。

    如果你同意這種對視圖的松散描述,你也就會同意絕大多數(shù)模板方案并沒有有效的分離視圖和模型。模板標(biāo)簽將被替換成什么存放在模型中。

    在你實(shí)現(xiàn)視圖時(shí)問自己幾個(gè)問題:“全體視圖的替換容易嗎?”“實(shí)現(xiàn)一個(gè)新視圖要多久?” “能很容易的替換視圖的描述語言嗎?(比如在同一個(gè)視圖中用SOAP文檔替換HTML文檔)”


    模型(Model)

    模型代表了程序邏輯。(在企業(yè)級程序中經(jīng)常稱為業(yè)務(wù)層(business layer))

    總的來說,模型的任務(wù)是把原有數(shù)據(jù)轉(zhuǎn)換成包含某些意義的數(shù)據(jù),這些數(shù)據(jù)將被視圖所顯示。通常,模型將封裝數(shù)據(jù)查詢,可能通過一些抽象數(shù)據(jù)類(數(shù)據(jù)訪問層)來實(shí)現(xiàn)查詢。舉例說,你希望計(jì)算英國年度降雨量(只是為了給你自己找個(gè)好點(diǎn)的度假地),模型將接收十年中每天的降雨量,計(jì)算出平均值,再傳遞給視圖。


    控制器(controller)

    簡單的說控制器是Web應(yīng)用中進(jìn)入的HTTP請求最先調(diào)用的一部分。它檢查收到的請求,比如一些GET變量,做出合適的反饋。在寫出你的第一個(gè)控制器之前,你很難開始編寫其他的PHP代碼。最常見的用法是index.php中像switch語句的結(jié)構(gòu):

    <?php
    switch ($_GET['viewpage']) {
    case "news":
    $page=new NewsRenderer;
    break;
    case "links":
    $page=new LinksRenderer;
    break;
    default:
    $page=new HomePageRenderer;
    break;
    }
    $page->display();
    ?>


    這段代碼混用了面向過程和對象的代碼,但是對于小的站點(diǎn)來說,這通常是最好的選擇。雖然上邊的代碼還可以優(yōu)化。

    控制器實(shí)際上是用來觸發(fā)模型的數(shù)據(jù)和視圖元素之間的綁定的控件。


    例子

    這里是一個(gè)使用MVC模式的簡單例子。
    首先我們需要一個(gè)數(shù)據(jù)庫訪問類,它是一個(gè)普通類。

    <?php
    /**
    *  A simple class for querying MySQL
    */
    class DataAccess {
    /**
    * Private
    * $db stores a database resource
    */
    var $db;
    /**
    * Private
    * $query stores a query resource
    */
    var $query; // Query resource
    //! A constructor.
    /**
    * Constucts a new DataAccess object
    * @param $host string hostname for dbserver
    * @param $user string dbserver user
    * @param $pass string dbserver user password
    * @param $db string database name
    */
    function DataAccess ($host,$user,$pass,$db) {
    $this->db=mysql_pconnect($host,$user,$pass);
    mysql_select_db($db,$this->db);
    }
    //! An accessor
    /**
    * Fetches a query resources and stores it in a local member
    * @param $sql string the database query to run
    * @return void
    */
    function fetch($sql) {
    $this->query=mysql_unbuffered_query($sql,$this->db); // Perform query here
    }
    //! An accessor
    /**
    * Returns an associative array of a query row
    * @return mixed
    */
    function getRow () {
    if ( $row=mysql_fetch_array($this->query,MYSQL_ASSOC) )
    return $row;
    else
    return false;
    }
    }
    ?>


    在它上邊放上模型。

    <?php
    /**
    *  Fetches "products" from the database
    */
    class ProductModel {
    /**
    * Private
    * $dao an instance of the DataAccess class
    */
    var $dao;
    //! A constructor.
    /**
    * Constucts a new ProductModel object
    * @param $dbobject an instance of the DataAccess class
    */
    function ProductModel (&$dao) {
    $this->dao=& $dao;
    }
    //! A manipulator
    /**
    * Tells the $dboject to store this query as a resource
    * @param $start the row to start from
    * @param $rows the number of rows to fetch
    * @return void
    */
    function listProducts($start=1,$rows=50) {
    $this->dao->fetch("SELECT * FROM products LIMIT ".$start.", ".$rows);
    }
    //! A manipulator
    /**
    * Tells the $dboject to store this query as a resource
    * @param $id a primary key for a row
    * @return void
    */
    function listProduct($id) {
    $this->dao->fetch("SELECT * FROM products WHERE PRODUCTID='".$id."'");
    }
    //! A manipulator
    /**
    * Fetches a product as an associative array from the $dbobject
    * @return mixed
    */
    function getProduct() {
    if ( $product=$this->dao->getRow() )
    return $product;
    else
    return false;
    }
    }
    ?>


    有一點(diǎn)要注意的是,在模型和數(shù)據(jù)訪問類之間,它們的交互從不會多于一行??沒有多行被傳送,那樣會很快使程式慢下來。同樣的程式對于使用模式的類,它只需要在內(nèi)存中保留一行(Row)??其他的交給已保存的查詢資源(query resource)??換句話說,我們讓MYSQL替我們保持結(jié)果。

    接下來是視圖??我去掉了HTML以節(jié)省空間,你可以查看這篇文章的完整代碼。

    <?php
    /**
    *  Binds product data to HTML rendering
    */
    class ProductView {
    /**
    * Private
    * $model an instance of the ProductModel class
    */
    var $model;
    /**
    * Private
    * $output rendered HTML is stored here for display
    */
    var $output;
    //! A constructor.
    /**
    * Constucts a new ProductView object
    * @param $model an instance of the ProductModel class
    */
    function ProductView (&$model) {
    $this->model=& $model;
    }
    //! A manipulator
    /**
    * Builds the top of an HTML page
    * @return void
    */
    function header () {
    }
    //! A manipulator
    /**
    * Builds the bottom of an HTML page
    * @return void
    */
    function footer () {
    }
    //! A manipulator
    /**
    * Displays a single product
    * @return void
    */
    function productItem($id=1) {
    $this->model->listProduct($id);
    while ( $product=$this->model->getProduct() ) {
    // Bind data to HTML
    }
    }
    //! A manipulator
    /**
    * Builds a product table
    * @return void
    */
    function productTable($rownum=1) {
    $rowsperpage='20';
    $this->model->listProducts($rownum,$rowsperpage);
    while ( $product=$this->model->getProduct() ) {
    // Bind data to HTML
    }
    }
    //! An accessor
    /**
    * Returns the rendered HTML
    * @return string
    */
    function display () {
    return $this->output;
    }
    }
    ?>


    最后是控制器,我們將把視圖實(shí)現(xiàn)為一個(gè)子類。

    <?php
    /**
    *  Controls the application
    */
    class ProductController extends ProductView {
    //! A constructor.
    /**
    * Constucts a new ProductController object
    * @param $model an instance of the ProductModel class
    * @param $getvars the incoming HTTP GET method variables
    */
    function ProductController (&$model,$getvars=null) {
    ProductView::ProductView($model);
    $this->header();
    switch ( $getvars['view'] ) {
    case "product":
    $this->productItem($getvars['id']);
    break;
    default:
    if ( empty ($getvars['rownum']) ) {
    $this->productTable();
    } else {
    $this->productTable($getvars['rownum']);
    }
    break;
    }
    $this->footer();
    }
    }
    ?>


    Click to fullsize


    注意這不是實(shí)現(xiàn)MVC的唯一方式??比如你可以用控制器實(shí)現(xiàn)模型同時(shí)整合視圖。這只是演示模式的一種方法。

    我們的index.php 文件看起來像這樣:

    <?php
    require_once('lib/DataAccess.php');
    require_once('lib/ProductModel.php');
    require_once('lib/ProductView.php');
    require_once('lib/ProductController.php');
    $dao=& new DataAccess ('localhost','user','pass','dbname');
    $productModel=& new ProductModel($dao);
    $productController=& new ProductController($productModel,$_GET);
    echo $productController->display();
    ?>


    漂亮而簡單。

    我們有一些使用控制器的技巧,在PHP中你可以這樣做:

    $this->{$_GET['method']}($_GET['param']); 


    一個(gè)建議是你最好定義程序URL的名字空間形式(namespace),那樣它會比較規(guī)范比如:

    "index.php?class=ProductView&method=productItem&id=4"


    通過它我們可以這樣處理我們的控制器:

    $view=new $_GET['class'];
    $view->{$_GET['method']($_GET['id']);


    有時(shí)候,建立控制器是件很困難的事情,比如當(dāng)你在開發(fā)速度和適應(yīng)性之間權(quán)衡時(shí)。一個(gè)獲得靈感的好去處是Apache group 的Java Struts,它的控制器完全是由XML文檔定義的。

    相關(guān)附件:本文完整實(shí)例

    本文英文原版地址:http://www.phppatterns.com/index.php/article/articleview/11/

    posted on 2007-10-12 14:37 風(fēng)人園 閱讀(264) 評論(0)  編輯  收藏 所屬分類: PHP


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 91制片厂制作传媒免费版樱花 | 久久精品国产亚洲沈樵| 丁香花在线观看免费观看| 最新国产乱人伦偷精品免费网站 | 午夜高清免费在线观看| 日韩免费高清大片在线| 国产精品美女久久久免费| 亚洲成av人无码亚洲成av人| 亚洲精品中文字幕无码AV| 国产成人A人亚洲精品无码| 免费人成视频在线观看不卡| 成人人免费夜夜视频观看| 18观看免费永久视频| 国产精成人品日日拍夜夜免费| 手机永久免费的AV在线电影网| 亚洲乱码无人区卡1卡2卡3| 亚洲冬月枫中文字幕在线看| 亚洲爆乳精品无码一区二区三区 | 99久久免费国产特黄| 男女交性无遮挡免费视频| 亚洲αⅴ无码乱码在线观看性色| 亚洲人成电影在线观看青青| 久久精品国产亚洲av成人| 亚洲深深色噜噜狠狠爱网站| 亚洲中文字幕丝袜制服一区| 日本中文一区二区三区亚洲| 免费v片视频在线观看视频| 日日AV拍夜夜添久久免费| 免费看大黄高清网站视频在线| 午夜色a大片在线观看免费| 成人黄软件网18免费下载成人黄18免费视频 | 免费福利在线播放| 在线观看成人免费视频不卡| 美丽的姑娘免费观看在线播放| 色欲国产麻豆一精品一AV一免费| 精品国产麻豆免费人成网站| 99re6在线视频精品免费| 日本不卡免费新一区二区三区| 久久青草国产免费观看| 99热这里有免费国产精品| 99re热精品视频国产免费|