Zend Framework開發入門經典教程,zendframework
本文講述了Zend Framework開發入門相關知識點。分享給大家供大家參考,具體如下:
Zend Framework發布了!雖然仍處於開發初期,這個教程仍突出講解目前幾個最好的功能,並指導你完成一個簡單程式的構建。
Zend最早在社區裡發布了ZF。基於同樣的想法,這個教程寫來用於展示ZF現有的功能。由於這個教程是線上發布,我將在ZF變化時對其進行更新,以便儘可能有效。
要求
Zend Framework要求PHP5。為了更好利用本教程的代碼,你還需要Apache網頁伺服器。因為示範程式(一個新聞管理系統)用到了mod_rewrite。
這個教程的代碼可以自由下載,所以你可以自己試一下。你可以從Brain Buld的網站下載到代碼:http://brainbulb.com/zend-framework-tutorial.tar.gz。
下載ZF
當你開始這篇教程時,你需要下載ZF的最新版本。你可以用瀏覽器手工從http://framework.zend.com/download選擇tar.gz或zip檔案進行下載,或者使用下列命令:
$ wget http://framework.zend.com/download/tgz$ tar -xvzf ZendFramework-0.1.2.tar.gz
提示:Zend計劃提供自有PEAR通道簡化下載。
一旦你下載了預覽版,把library目錄放到方便的地方。在這個教程,我把library重新命名為lib以便有個簡潔的目錄結構:
app/
views/
controllers/
www/
.htaccess
index.php
lib/
www目錄是主目錄,controllers和views目錄是以後會用到的空目錄,而lib目錄來自你下載的預覽版。
開始
我要介紹的第一個組件是Zend_Controller。從很多方面看,它為你開發的程式提供了基礎,同時也部分決定了Zend Framework不只是個組件的集合。但是,你在用之前需要將所有的得到的請求都放到一個簡單的PHP指令碼。本教程用的是mod_rewrite。
用mod_rewrite自身是一種藝術,但幸運的是,這個特殊的任務特別簡單。如果你對mod_rewrite或Apache的一般配置不熟悉,在主目錄下建立一個.htaccess檔案,並添加以下內容:
RewriteEngine onRewriteRule !/.(js|ico|gif|jpg|png|css)$ index.php
提示: Zend_Controller的一個TODO項目就是取消對mod_rewrite的依賴。為了提供一個預覽版的範例,本教程用了mod_rewrite。
如果你直接把這些內容添加到httpd.conf,你必須重啟網頁伺服器。但如果你用.htaccess檔案,則什麼都不必做。你可以放一些具體的文本到index.php並訪問任意路徑如/foo/bar做一下快速測試。如你的網域名稱為example.org,則訪問http://example.org/foo/bar。
你還要設定ZF庫的路徑到include_path。你可以在php.ini設定,也可以直接在你的.htaccess檔案放下列內容:
php_value include_path "/path/to/lib"
Zend
Zend類包含了一些經常使用的靜態方法的集合。下面是唯一一個你要手工添加的類:
<?phpinclude 'Zend.php';?>
一旦你包含了Zend.php,你就已經包含了Zend類的所有的類方法。用loadClass()就可以簡單地載入其它類。例如,載入Zend_Controller_Front類:
<?phpinclude 'Zend.php';Zend::loadClass('Zend_Controller_Front');?>
include_path能理解loadclass()及ZF的組織和目錄結構。我用它載入所有其它類。
Zend_Controller
使用這個controller非常直觀。事實上,我寫本教程時並沒有用到它豐富的文檔。
提示:文檔目前已經可以在http://framework.zend.com/manual/zend.controller.html看到。
我一開始是用一個叫Zend_Controller_Front的front controller。為了理解它是怎麼工作的,請把下列代碼放在你的index.php檔案:
<?phpinclude 'Zend.php';Zend::loadClass('Zend_Controller_Front');$controller = Zend_Controller_Front::getInstance();$controller->setControllerDirectory('/path/to/controllers');$controller->dispatch();?>
如果你更喜歡對象鏈結,可以用以下代碼代替:
<?phpinclude 'Zend.php';Zend::loadClass('Zend_Controller_Front');$controller = Zend_Controller_Front::getInstance() ->setControllerDirectory('/path/to/controllers') ->dispatch();?>
現在如果你訪問/foo/bar,會有錯誤發生。沒錯!它讓你知道發生了什麼事。主要的問題是找不到IndexController.php檔案。
在你建立這個檔案之前,應先理解一下ZF想讓你怎樣組織這些事情。ZF把訪問請求給拆分開來。假如訪問的是/foo/bar,則foo是controller,而bar是action。它們的預設值都是index.
如果foo是controller,ZF就會去尋找controllers目錄下的FooController.php檔案。因為這個檔案不存在,ZF就退回到IndexController.php。結果都沒有找到,就報錯了。
接下來,在controllers目錄建立IndexController.php檔案(可以用setControllerDirectory()設定):
<?phpZend::loadClass('Zend_Controller_Action');class IndexController extends Zend_Controller_Action { public function indexAction() { echo 'IndexController::indexAction()'; }}?>
就如剛才說明的,IndexController類處理來自index controller或controller不存在的請求。indexAction()方法處理action為index的訪問。要記住的是index是controller和action的預設值。如果你訪問/,/index或/index/index,indexAction()方法就會被執行。 (最後面的斜杠並不會改變這個行為。) 而訪問其他任何資源只會導致出錯。
在繼續做之前,還要在IndexController加上另外一個有用的類方法。不管什麼時候訪問一個不存在的控制器,都要調用noRouteAction()類方法。例如,在FooController.php不存在的條件下,訪問/foo/bar就會執行noRouteAction()。但是訪問/index/foo仍會出錯,因為foo是action,而不是controller.
將noRouteAction()添加到IndexController.php:
<?phpZend::loadClass('Zend_Controller_Action');class IndexController extends Zend_Controller_Action { public function indexAction() { echo 'IndexController::indexAction()'; } public function noRouteAction() { $this->_redirect('/'); }}?>
例子中使用$this->_redirect('/')來描述執行noRouteAction()時,可能發生的行為。這會將對不存在controllers的訪問重新導向到根文檔(首頁)。
現在建立FooController.php:
<?phpZend::loadClass('Zend_Controller_Action');class FooController extends Zend_Controller_Action { public function indexAction() { echo 'FooController::indexAction()'; } public function barAction() { echo 'FooController::barAction()'; }}?>
如果你再次訪問/foo/bar,你會發現執行了barAction(),因為bar是action。現在你不只支援了友好的URL,還可以只用幾行代碼就做得這麼有條理。酷吧!
你也可以建立一個__call()類方法來處理像/foo/baz這樣未定義的action。
<?phpZend::loadClass('Zend_Controller_Action');class FooController extends Zend_Controller_Action { public function indexAction() { echo 'FooController::indexAction()'; } public function barAction() { echo 'FooController::barAction()'; } public function __call($action, $arguments) { echo 'FooController:__call()'; }}?>
現在你只要幾行代碼就可以很好地處理使用者的訪問了,準備好繼續。
Zend_View
Zend_View是一個用來協助你組織好你的view邏輯的類。這對於模板-系統是不可知的,為了簡單起見,本教程不使用模板。如果你喜歡的話,不妨用一下。
記住,現在所有的訪問都是由front controller進行處理。因此應用程式框架已經存在了,另外也必須遵守它。為了展示Zend_View的一個基本應用,將IndexController.php修改如下:
<?phpZend::loadClass('Zend_Controller_Action');Zend::loadClass('Zend_View');class IndexController extends Zend_Controller_Action { public function indexAction() { $view = new Zend_View(); $view->setScriptPath('/path/to/views'); echo $view->render('example.php'); } public function noRouteAction() { $this->_redirect('/'); }}?>
在views目錄建立example.php檔案:
This Is an Example This is an example.
現在,如果你訪問自己網站的根資源,你會看到example.php的內容。這仍沒什麼用,但你要清楚你要在以一種結構和組織非常清楚的方式在開發網路應用。
為了讓Zend_View的應用更清楚一點,,修改你的模板(example.php)包含以下內容:
<?php echo $this->escape($this->title); ?> <?php echo $this->escape($this->body); ?>
現在已經添加了兩個功能。$this->escape()類方法用於所有的輸出。即使你自己建立輸出,就像這個例子一樣。避開所有輸出也是一個很好的習慣,它可以在預設情況下協助你防止跨站指令碼攻擊(XSS)。
$this->title和$this->body屬性用來展示動態資料。這些也可以在controller中定義,所以我們修改IndexController.php以指定它們:
<?phpZend::loadClass('Zend_Controller_Action');Zend::loadClass('Zend_View');class IndexController extends Zend_Controller_Action { public function indexAction() { $view = new Zend_View(); $view->setScriptPath('/path/to/views'); $view->title = 'Dynamic Title'; $view->body = 'This is a dynamic body.'; echo $view->render('example.php'); } public function noRouteAction() { $this->_redirect('/'); }}?>
現在你再次訪問根目錄,應該就可以看到模板所使用的這些值了。因為你在模板中使用的$this就是在Zend_View範圍內所執行的執行個體。
要記住example.php只是一個普通的PHP指令碼,所以你完全可以做你想做的。只是應努力只在要求顯示資料時才使用模板。你的controller (controller分發的模組)應處理你全部的商務邏輯。
在繼續之前,我想做最後一個關於Zend_View的提示。在controller的每個類方法內初始化$view對象需要額外輸入一些內容,而我們的主要目標是讓快速開發網路應用更簡單。如果所有模板都放在一個目錄下,是否要在每個例子中都調用setScriptPath()也存在爭議。
幸運的是,Zend類包含了一個寄存器來協助減少工作量。你可以用register()方法把你的$viewObject Storage Service在寄存器:
<?phpZend::register('view', $view);?>
用registry()方法進行檢索:
<?php$view = Zend::registry('view');?>
基於這點,本教程使用寄存器。
Zend_InputFilter
本教程討論的最後一個組件是Zend_InputFilter。這個類提供了一種簡單而有效輸入過濾方法。你可以通過提供一組待過濾資料來進行初始化。
<?php$filterPost = new Zend_InputFilter($_POST);?>
這會將($_POST)設定為NULL,所以就不能直接進入了。Zend_InputFilter提供了一個簡單、集中的根據特定規則過濾資料的類方法集。例如,你可以用getAlpha()來擷取$_POST['name']中的字母:
<?php/* $_POST['name'] = 'John123Doe'; */$filterPost = new Zend_InputFilter($_POST);/* $_POST = NULL; */$alphaName = $filterPost->getAlpha('name');/* $alphaName = 'JohnDoe'; */?>
每一個類方法的參數都是對應要過濾的元素的關鍵詞。對象(例子中的$filterPost)可以保護資料不被篡改,並能更好地控制對資料的操作及一致性。因此,當你操縱輸入資料,應始終使用Zend_InputFilter。
提示:Zend_Filter提供與Zend_InputFilter方法一樣的靜態方法。
構建新聞管理系統
雖然預覽版提供了許多組件(甚至許多已經被開發),我們已經討論了構建一個簡單程式所需要的全部組件。在這裡,你會對ZF的基本結構和設計有更清楚的理解。
每個人開發的程式都會有所不同,而Zend Framework試圖包容這些差異。同樣,這個教程是根據我的喜好寫的,請根據自己的偏好自行調整。
當我開發程式時,我會先做介面。這並不意味著我把時間都花在標籤、樣式表和圖片上,而是我從一個使用者的角度去考慮問題。因此我把程式看成是頁面的集合,每一頁都是一個獨立的網址。這個新聞系統就是由以下網址組成的:
/
/add/news
/add/comment
/admin
/admin/approve
/view/{id}
你可以直接把這些網址和controller聯絡起來。IndexController列出新聞,AddController添加新聞和評論,AdminController處理一些如批准新聞之類的管理,ViewController特定新聞和對應評論的顯示。
如果你的FooController.php還在,把它刪除。修改IndexController.php,為商務邏輯以添加相應的action和一些注釋:
<?phpZend::loadClass('Zend_Controller_Action');class IndexController extends Zend_Controller_Action { public function indexAction() { /* List the news. */ } public function noRouteAction() { $this->_redirect('/'); }}?>
接下來,建立AddController.php檔案:
<?phpZend::loadClass('Zend_Controller_Action');class AddController extends Zend_Controller_Action{ function indexAction() { $this->_redirect('/'); } function commentAction() { /* Add a comment. */ } function newsAction() { /* Add news. */ } function __call($action, $arguments) { $this->_redirect('/'); }}?>
記住AddController的indexAction()方法不能調用。當訪問/add時會執行這個類方法。因為使用者可以手工訪問這個網址,這是有可能的,所以你要把使用者重新導向到首頁、顯示錯誤或你認為合適的行為。
接下來,建立AdminController.php檔案:
<?phpZend::loadClass('Zend_Controller_Action');class AdminController extends Zend_Controller_Action{ function indexAction() { /* Display admin interface. */ } function approveAction() { /* Approve news. */ } function __call($action, $arguments) { $this->_redirect('/'); }}?>
最後,建立ViewController.php檔案:
<?phpZend::loadClass('Zend_Controller_Action');class ViewController extends Zend_Controller_Action{ function indexAction() { $this->_redirect('/'); } function __call($id, $arguments) { /* Display news and comments for $id. */ }}?>
和AddController一樣,index()方法不能調用,所以你可以使用你認為合適的action。ViewController和其它的有點不同,因為你不知道什麼才是有效action。為了支援像/view/23這樣的網址,你要使用__call()來支援動態action。
資料庫操作
因為Zend Framework的資料庫組件還不穩定,而我希望這個示範可以做得簡單一點。我使用了一個簡單的類,用SQLite進行新聞條目和評論的儲存和查詢。
<?phpclass Database{ private $_db; public function __construct($filename) { $this->_db = new SQLiteDatabase($filename); } public function addComment($name, $comment, $newsId) { $name = sqlite_escape_string($name); $comment = sqlite_escape_string($comment); $newsId = sqlite_escape_string($newsId); $sql = "INSERT INTO comments (name, comment, newsId) VALUES ('$name', '$comment', '$newsId')"; return $this->_db->query($sql); } public function addNews($title, $content) { $title = sqlite_escape_string($title); $content = sqlite_escape_string($content); $sql = "INSERT INTO news (title, content) VALUES ('$title', '$content')"; return $this->_db->query($sql); } public function approveNews($ids) { foreach ($ids as $id) { $id = sqlite_escape_string($id); $sql = "UPDATE news SET approval = 'T' WHERE id = '$id'"; if (!$this->_db->query($sql)) { return FALSE; } } return TRUE; } public function getComments($newsId) { $newsId = sqlite_escape_string($newsId); $sql = "SELECT name, comment FROM comments WHERE newsId = '$newsId'"; if ($result = $this->_db->query($sql)) { return $result->fetchAll(); } return FALSE; } public function getNews($id = 'ALL') { $id = sqlite_escape_string($id); switch ($id) { case 'ALL': $sql = "SELECT id, title FROM news WHERE approval = 'T'"; break; case 'NEW': $sql = "SELECT * FROM news WHERE approval != 'T'"; break; default: $sql = "SELECT * FROM news WHERE id = '$id'"; break; } if ($result = $this->_db->query($sql)) { if ($result->numRows() != 1) { return $result->fetchAll(); } else { return $result->fetch(); } } return FALSE; }}?>
(你可以用自己的解決方案隨意替換這個類。這裡只是為你提供一個完整樣本的介紹,並非建議要這麼實現。)
這個類的構造器需要SQLite資料庫的完整路徑和檔案名稱,你必須自己進行建立。
<?php$db = new SQLiteDatabase('/path/to/db.sqlite');$db->query("CREATE TABLE news ( id INTEGER PRIMARY KEY, title VARCHAR(255), content TEXT, approval CHAR(1) DEFAULT 'F' )");$db->query("CREATE TABLE comments ( id INTEGER PRIMARY KEY, name VARCHAR(255), comment TEXT, newsId INTEGER )");?>
你只需要做一次,以後直接給出Database類構造器的完整路徑和檔案名稱即可:
<?php$db = new Database('/path/to/db.sqlite');?>
整合
為了進行整合,在lib目錄下建立Database.php,loadClass()就可以找到它。你的index.php檔案現在就會初始化$view和$db並儲存到寄存器。你也可以建立__autoload()函數自動載入你所需要的類:
<?phpinclude 'Zend.php';function __autoload($class){ Zend::loadClass($class);}$db = new Database('/path/to/db.sqlite');Zend::register('db', $db);$view = new Zend_View;$view->setScriptPath('/path/to/views');Zend::register('view', $view);$controller = Zend_Controller_Front::getInstance() ->setControllerDirectory('/path/to/controllers') ->dispatch();?>
接下來,在views目錄建立一些簡單的模板。index.php可以用來顯示index視圖:
News News
<?php foreach ($this->news as $entry) { ?> escape($entry['id']); ?>"> <?php echo $this->escape($entry['title']); ?>
<?php } ?> Add News
view.php模板可以用來顯示選定的新聞條目:
<?php echo $this->escape($this->news['title']); ?> <?php echo $this->escape($this->news['title']); ?>
<?php echo $this->escape($this->news['content']); ?>
Comments
<?php foreach ($this->comments as $comment) { ?> <?php echo $this->escape($comment['name']); ?> writes:
<?php echo $this->escape($comment['comment']); ?>
<?php } ?> Add a Comment
最後,admin.php模板可以用來批准新聞條目:
News Admin
提示:為了保持簡單,這個表單用密碼作為驗證機制。
使用到模板的地方,你只需要把注釋替換成幾行代碼。如IndexController.php就變成下面這樣:
<?phpclass IndexController extends Zend_Controller_Action { public function indexAction() { /* List the news. */ $db = Zend::registry('db'); $view = Zend::registry('view'); $view->news = $db->getNews(); echo $view->render('index.php'); } public function noRouteAction() { $this->_redirect('/'); }}?>
因為條理比較清楚,這個程式首頁的整個商務邏輯只有四行代碼。AddController.php更複雜一點,它需要更多的代碼:
<?phpclass AddController extends Zend_Controller_Action{ function indexAction() { $this->_redirect('/'); } function commentAction() { /* Add a comment. */ $filterPost = new Zend_InputFilter($_POST); $db = Zend::registry('db'); $name = $filterPost->getAlpha('name'); $comment = $filterPost->noTags('comment'); $newsId = $filterPost->getDigits('newsId'); $db->addComment($name, $comment, $newsId); $this->_redirect("/view/$newsId"); } function newsAction() { /* Add news. */ $filterPost = new Zend_InputFilter($_POST); $db = Zend::registry('db'); $title = $filterPost->noTags('title'); $content = $filterPost->noTags('content'); $db->addNews($title, $content); $this->_redirect('/'); } function __call($action, $arguments) { $this->_redirect('/'); }}?>
因為使用者在提交表單後被重新導向,這個controller不需要視圖。
在AdminController.php,你要處理顯示管理介面和批准新聞兩個action:
<?phpclass AdminController extends Zend_Controller_Action{ function indexAction() { /* Display admin interface. */ $db = Zend::registry('db'); $view = Zend::registry('view'); $view->news = $db->getNews('NEW'); echo $view->render('admin.php'); } function approveAction() { /* Approve news. */ $filterPost = new Zend_InputFilter($_POST); $db = Zend::registry('db'); if ($filterPost->getRaw('password') == 'mypass') { $db->approveNews($filterPost->getRaw('ids')); $this->_redirect('/'); } else { echo 'The password is incorrect.'; } } function __call($action, $arguments) { $this->_redirect('/'); }}?>
最後是ViewController.php:
<?phpclass ViewController extends Zend_Controller_Action{ function indexAction() { $this->_redirect('/'); } function __call($id, $arguments) { /* Display news and comments for $id. */ $id = Zend_Filter::getDigits($id); $db = Zend::registry('db'); $view = Zend::registry('view'); $view->news = $db->getNews($id); $view->comments = $db->getComments($id); $view->id = $id; echo $view->render('view.php'); }}?>
雖然很簡單,但我們還是提供了一個功能較全的新聞和評論程式。最好的地方是由於有較好的設計,增加功能變得很簡單。而且隨著Zend Framework越來越成熟,只會變得更好。
更多資訊
這個教程只是討論了ZF表面的一些功能,但現在也有一些其它的資源可供參考。在http://framework.zend.com/manual/有手冊可以查詢,Rob Allen在http://akrabat.com/zend-framework/介紹了一些他使用Zend Framework的經驗,而Richard Thomas也在http://www.cyberlot.net/zendframenotes提供了一些有用的筆記。如果你有自己的想法,可以訪問Zend Framework的新論壇:http://www.phparch.com/discuss/index.php/f/289//。
結束語
要對預覽版進行評價是很容易的事,我在寫這個教程時也遇到很多困難。總的來說,我想Zend Framework顯示了承諾,加入的每個人都是想繼續完善它。
更多關於zend相關內容感興趣的讀者可查看本站專題:《Zend FrameWork架構入門教程》、《php優秀開發架構總結》、《Yii架構入門及常用技巧總結》、《ThinkPHP入門教程》、《php物件導向程式設計入門教程》、《php+mysql資料庫操作入門教程》及《php常見資料庫操作技巧匯總》
希望本文所述對大家基於Zend Framework架構的PHP程式設計有所協助。
您可能感興趣的文章:
- Zend Framework架構教程之Zend_Db_Table_Rowset用法執行個體分析
- Zend Framework教程之Zend_Db_Table_Row用法執行個體分析
- Zend Framework教程之Zend_Db_Table用法詳解
- Zend Framework教程之Zend_Form組件實現表單提交並顯示錯誤提示的方法
- Zend Framework架構Smarty擴充實現方法
- Zend Framework架構路由機制程式碼分析
- Zend Framework實現具有準系統的留言本(附demo源碼下載)
- Zend Framework實現將session儲存在memcache中的方法
- Zend Framework分頁類用法詳解
- Zend Framework實現多檔案上傳功能執行個體
- Zend Framework入門之環境配置及第一個Hello World樣本(附demo源碼下載)
- Zend Framework教程之串連資料庫並執行增刪查的方法(附demo源碼下載)
- Zend Framework教程之Zend_Db_Table表關聯執行個體詳解
http://www.bkjia.com/PHPjc/1113710.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/1113710.htmlTechArticleZend Framework開發入門經典教程,zendframework 本文講述了Zend Framework開發入門相關知識點。分享給大家供大家參考,具體如下: Zend Framework發布...