MVCモードのPHP実現

7878 ワード

MVCモードはウェブサイトアーキテクチャでよく見られる.これにより、3つの階層構造のアプリケーションを構築し、コードから有用な階層を分離し、デザイナーと開発者の共同作業を支援し、既存のプログラムを維持し、拡張する能力を高めることができます.
ビュー(View)
「ビュー」は主にWebブラウザに送られた最終結果を指しますか?例えば、私たちのスクリプトが生成したHTMLです.ビューといえばテンプレートを思い浮かべる人が多いが,テンプレートスキームをビューと呼ぶ正確性は疑わしい.
ビューにとって最も重要なことは、「自己意識(self aware)」であるべきかもしれません.ビューがレンダリングされると、ビューの要素はより大きなフレームワークでの役割を意識することができます.
XMLを例にとると,XMLが解析されたとき,DOM APIはこのような認知を持っていたと言えるだろうか.DOMツリーのノードは、どこにあるか、何が含まれているかを知っています.(XMLドキュメントのノードをSAXで解析する場合、そのノードを解析する場合にのみ意味があります.)
ほとんどのテンプレートスキームでは、簡単なプロセス言語とこのようなテンプレートラベルが使用されます.
<p>{some_text}</p>

<p>{some_more_text}</p>

ドキュメントには意味がありません.PHPは他のもので置き換えられるだけです.
このようなビューのばらばらな説明に同意すれば、ほとんどのテンプレートスキームがビューとモデルを効果的に分離していないことにも同意します.テンプレートラベルは、モデルに格納されるものに置き換えられます.
ビューを実装するときに、「全体のビューの置き換えは簡単ですか?」といくつか質問します.「新しいビューを実装するにはどのくらいかかりますか?」「ビューの記述言語を簡単に置き換えることができますか?(例えば同じビューでHTMLドキュメントをSOAPドキュメントで置き換える)
モデル(Model)
モデルはプログラムロジックを表します.(エンタープライズ・プログラムではビジネス・レイヤと呼ばれることが多い)
総じて、モデルのタスクは、既存のデータをビューに表示されるいくつかの意味を含むデータに変換することです.通常、モデルはデータ・クエリーをカプセル化し、いくつかの抽象データ・クラス(データ・アクセス・レイヤ)によってクエリーを実現することができます.例えば、イギリスの年間降雨量(自分で良いリゾートを探すためだけ)を計算したい場合は、モデルは10年間の毎日の降雨量を受信し、平均値を計算してからビューに渡します.
コントローラ
簡単に言えば、コントローラは、Webアプリケーションに入力されたHTTPリクエストの最初の呼び出しの一部である.GET変数などの受信したリクエストをチェックし、適切なフィードバックを行います.最初のコントローラを書く前に、他のPHPコードを書くのは難しいです.最も一般的な使い方はindexです.phpのswitch文のような構造:
<?php

switch ($_GET['viewpage']) {

case "news":

$page=new NewsRenderer;

break;

case "links":

$page=new LinksRenderer;

break;

default:

$page=new HomePageRenderer;

break;

}

$page->display();

?>

このコードはプロシージャとオブジェクト向けのコードを混用していますが、小さなサイトでは通常最適です.上のコードは最適化できますが.
コントローラは、実際にはモデルのデータとビュー要素との間のバインドをトリガするためのコントロールです.

ここではMVCモードを用いた簡単な例である.
まず、通常のクラスであるデータベース・アクセス・クラスが必要です.
<?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;

}

}

?>

モデルとデータ・アクセス・クラスの間で、それらのインタラクションは1行以上ではないことに注意してください.多くの行が転送されていないので、すぐにプログラムが遅くなります.同じプログラムは使用モードのクラスに対して、メモリに1行(Row)?保存されたクエリーリソース(query resource)?言い換えれば、私たちはMYSQLに結果を維持させます.
次はビュー??私はHTMLを削除してスペースを節約して、あなたはこの文章の完全なコードを見ることができます.
<?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;

}

}

?>

最後にコントローラで、ビューをサブクラスに実装します.
<?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();

}

}

?>

MVCを実現する唯一の方法ではないことに注意してください??たとえば、コントローラを使用してモデルを実装し、ビューを統合できます.これはプレゼンテーションモードの1つの方法にすぎません.
私たちの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']); 

1つの提案は、プログラムURLの名前空間形式(namespace)を定義したほうがいいということです.これにより、次のような規範が比較されます.
"index.php?class=ProductView&method=productItem&id=4"

コントローラをこのように処理できます.
$view=new $_GET['class'];

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

開発速度と適応性のバランスをとるなど、コントローラを構築するのは難しい場合があります.インスピレーションを得る良い場所はApacheグループのJava Strutsで、そのコントローラは完全にXMLドキュメントによって定義されています.
関連添付ファイル:本明細書の完全な例
本文の英文原版住所:http://www.phppatterns.com/index.php/article/articleview/11/