首頁 > Zend Framework > [PHP-ZF] Front Controller 的基本應用技

[PHP-ZF] Front Controller 的基本應用技

2008年2月27日 jaceju 發表評論 閱讀評論

剛學 Zend Framework 的朋友通常會遇到兩個麻煩:目錄結構的安排,還有就是怎麼在 index.php (bootstrap) 中使用 Front Controller ?

目錄結構的安排下次有機會再談,這裡我來說說 Front Controller 的用法。

註:在此之前,請大家先看過 Rob Allen 寫的 Getting Started with the Zend Framework 一文 (PDF 版本) ;本文將會以該篇教學為基礎,一步一步來說明。

什麼是 Front Controller

整體而言 Front Controller 比較像是一個中介的角色,以下是它常見的幾個功能:

  1. 處理應用程式的初始化設定並執行之。
  2. 管理應用程式執行路徑。
  3. 管理輸入 (Request) ,使得使用者的動作得以分派 ( Dispatch) 到 Action Controller 中。
  4. 管理輸出 (Response) ,使得應用程式能將結果傳送出來。
  5. 可以接受 Plugins 來擴充 Front Controller 的行為。

Front Controller 裡還有更深入的參數設定機制,不過本文暫且先略過不談。

基本的 Front Controller 用法

我們先來看看 Rob 在 Getting Started with the Zend Framework 裡是怎麼用 Front Controller 的:

<?php
error_reporting(E_ALL|E_STRICT);
date_default_timezone_set('Europe/London');
set_include_path('.' . PATH_SEPARATOR . './library'
. PATH_SEPARATOR . './application/models/'
. PATH_SEPARATOR . get_include_path());
 
include "Zend/Loader.php";
Zend_Loader::loadClass('Zend_Controller_Front');
 
// setup controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->throwExceptions(true);
$frontController->setControllerDirectory('./application/controllers');
 
// run!
$frontController->dispatch();

撇開前面 PHP 的設定部份,我們可以看到 Front Controller 主要分成設定與執行兩個部份。

在設定的部份裡,首先我們可以看到 Front Controller 為 Singleton ,換句話說 Front Controller 在整個應用程式執行的過程中只會有一個實體存在。接著我們再呼叫 Front Controller 的 throwExceptions() 方法,它能為我們設定是否要將 Exception 直接丟出或是放到 Response 物件中。最後我們再設定應用程式的 Action Controller 所在路徑,讓 Front Controller 知道到哪裡能找到要執行的 action 。

當設定好 Front Controller 後,就可以呼叫它的 dispatch() 方法來執行整個應用程式了。

以上就是最簡單的 Front Controller 使用方法,接下來我會介紹目前我所使用的方法。

進階的 Front Controller 用法

先來看看程式碼:

<?php
error_reporting(E_ALL|E_STRICT);
date_default_timezone_set('Asia/Taipei');
 
// set include_path
define('ROOT_PATH', str_replace('\\', '/', dirname(__FILE__)));
$includePath = array(
    ROOT_PATH . '/lib',
    get_include_path(),
);
set_include_path(join(PATH_SEPARATOR, $includePath));
 
// autoload
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();
 
// setup controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->setControllerDirectory(array(
        'default' => './app/mod/default/controllers',
        'admin' => './app/mod/admin/controllers'))
    ->throwExceptions(false)
    ->setDefaultModule('default')
    ->returnResponse(true);
 
// run!
$response = $frontController->dispatch();
if ($response->isException()) {
    $response->renderExceptions(true);
}
$response->sendResponse();

基本上我在 PHP 一般設定的部份和 Rob 的差不多 (因為我也是從他的教學入門的) ,只是我在載入類別的地方做了一些修改而已 (例如自動載入) 。

設定部份

接下來我們來看 Front Controller 設定的部份:

// setup controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->setControllerDirectory(array(
        'default' => './app/mod/default/controllers',
        'admin'   => './app/mod/admin/controllers'))
    ->setDefaultModule('default')
    ->throwExceptions(false)
    ->returnResponse(true);

在 Rob 的教學中因為只需要單一的功能 (也就是專輯管理) ,因此他並沒有使用 Front Controller 的模組設定。而在我所開發的專案中通常會有前後台之分,因此我就應用了 Front Controller 裡的模組功能。使用 Front Controller 模組功能的方法很簡單,就是在 setControllerDirectory() 方法中,給它一個陣列參數;這個陣列參數的 key 即為模組名稱, value 則為模組中 Action Controller 的路徑。

然後我們要設定預設執行的模組,這裡使用的是 setDefaultModule() 方法。預設模組的好處是我們在網址上不必特別指定模組名稱,在上面的例子中即為 default 。如果不是預設的模組,那麼就要在網址中明確指定模組名稱;以 admin 這個模組來說,網址就要輸入: http://localhost/admin 。特別要注意的是網址上的模組名稱參考的是前段說明中的 key ,而非 value 裡的目錄名稱。

接下來的 throwExceptions() 方法是個 setter 和 getter 的合體,當我們給它參數值時 (true 或 false) 它就是 setter ,反之不提供任何參數時就會是 getter 。前面提到 throwExceptions() 在設定 true 值時, Front Controller 會直接丟出 Exception ,這時程式就會直接中斷 (或是用 try…catch 來接也行) ;而 throwExceptions() 設定 false 值時, Front Controller 則會將 Exception 放到 Response 物件裡,在稍後處理 Reponse 物件時才會看到 Exception 的內容。

註: throwExceptions() 方法在 setter 時會回傳 Front Controller 物件本身,而成為 getter 時則會回傳 boolean 值;這邊要特別小心,我也曾經在這裡中招。

最後的 returnResponse() 方法也是個 setter 與 getter 的合體,它主要是設定 Front Controller 的 dispatch() 方法要不要回傳一個 Response 物件。這裡我的做法是永遠回傳 Response 物件 (也就是設定 true 值) ,這樣後面執行的程式碼才不會發生錯誤。

執行部份

// run!
$response = $frontController->dispatch();
if ($response->isException()) {
    $response->renderExceptions(true);
}
$response->sendResponse();

在執行的部份,由於我們前面已經用 returnResponse() 方法來設定要回傳 Response 物件,因此 Front Controller 在完成 dispatch() 方法後就會將輸出的結果包裝在 Response 物件中回傳給 index.php 。

接著我們從 Response 物件的 isException() 方法來判斷輸出的結果是不是一個 Exception ,是的話就透過 Response 物件的 renderExceptions() 方法設定是否要顯示 Exception 。如果在這裡 renderExceptions() 方法的參數被設定為 false 時,那麼 Front Controller 就會呼叫預設模組底下 ErrorController 中的 errorAction() 方法,這樣就不會讓前端的瀏覽者看到程式錯誤,而是我們自訂的錯誤頁。

註:這個功能在上線環境中特別重要,你可以在這裡用 Response 物件的 getException() 方法取得 Exception 的內容然後寫入 Log 中,而最後只顯示自訂的 Error 頁面。

最後我們再呼叫 Response 物件的 sendResponse() 方法來將輸出的結果傳送給瀏覽器或 Console ,不論它是不是個 Exception 。

結論

以往我們在寫程式時,最頭痛的就是一開始的流程要怎麼寫?程式出現錯誤時要如何呈現?上線環境和開發環境要如何區別?而 Front Controller 正好為我們解決了許多這樣的麻煩;不過相對的它的使用方式也容易讓一般開發者感到迷惑,很多剛接觸的朋友就會在這裡受到很多挫折 (我剛好也是其中之一) 。

其實 Zend Framework 的 Front Controller 是非常靈活且強大的,這裡僅僅只介紹了它的基本應用方式。後面如果有空的話,我會再介紹其他相關的功能。

範例下載

照慣例,範例的下載位址在這裡

Categories: Zend Framework Tags:
  1. 2008年2月27日14:14 | #1

    好文章一定是要推一下的 :)

  2. hermes
    2008年2月27日18:45 | #2

    感謝,這篇文章真是及時雨呀 :)

  3. 2008年2月27日22:10 | #3

    這種時候怎麼能不幫忙推一下呢!!!!

  4. jaceju
    2008年2月27日22:59 | #4

    To eddie, hermes, 凱:

    感謝你們的支持呀~

Spam Protection by WP-SpamFree