CodeIgniter 使用手冊版本 2.2.0


控制器(Controllers)

控制器(Controllers)是你的 application 的核心動力,決定了如何處理 HTTP 所發出的要求。

什麼是控制器(Controller)呢?

控制器(Controller)簡單來說就是 class 檔案,用來處理 URI。

看看這個 URI:

example.com/index.php/blog/

在上例中,CodeIgniter 會嘗試在找一個 blog.php 的控制器,並且找到後載入進來。

當控制器的名稱在 URI 中的第一段可以符合的話,它就會被載入。

我們的第一個程式:  Hello World!

先建立一個簡單的控制器(controller),用你的編輯器建立一個 blog.php 的檔案,把下列的程式碼塞進去:

存到 application/controllers/ 目錄底下。

現在打開像是底下的 URL 位置:

example.com/index.php/blog/

如果沒什麼出錯的話,你應該會看到 Hello World!

注意: Class 命名必須要字首大寫,換句話說,這樣是可以的命名:

<?php
class Blog extends CI_Controller {

}
?>

這個就是 不被接受的命名:

<?php
class blog extends CI_Controller {

}
?>

還有,請務必確定你的控制器是從母控制器(parent controller) 擴充出來,這樣才可以繼承母控制器的所有函數。

函數(Functions)

看看上面例子的函數名稱,它叫作是index()。這個 "index" 函數通常是預設載入, 假如 URI 的 第二個分段(second segment) 是 empty 的話。另一個秀出 "Hello World" 的方法,則是這樣:

example.com/index.php/blog/index/

URI 的第二個分段,決定了控制器裡頭的那一個函數得被呼叫出來。

接下來在試試看,新增一個函數到你的控制器裡頭:

現在載入底下的 URL 來看看這個 comment 函數:

example.com/index.php/blog/comments/

你應該會看到你的新的訊息!

傳遞 URL 段落到你的函數裡

假如你的 URI 包含超過兩個分段的話,他們會把這個當成是參數傳遞到你的函數裡頭。

舉例來說,如果你有個像這樣的 URL :

example.com/index.php/products/shoes/sandals/123

你的函數會收到第三跟第四的 URI 分段的內容,也就是會收到 "sandals" 以及 "123" 的參數:

<?php
class Products extends CI_Controller {

    public function shoes($sandals, $id)
    {
        echo $sandals;
        echo $id;
    }
}
?>

非常重要:  如果你使用 URI Routing 的功能,收到的內容則會是被 re-routed 過後的那個。

定義預設的控制器

CodeIgniter 可以修改預設載入的控制器,如要設定預設的控制器,請開啟 application/config/routes.php 的檔案,然後設定成底下的變數:

$route['default_controller'] = 'Blog';

這邊的 Blog 是在控制器類別裡頭,你所想要使用的名稱。修改完成後,不需要給予任何 URI 分段內容的預設情況之下,就可以看到 Hello World 的訊息了。

重新對映函數呼叫

如上頭所描述,在第二個URI分段的名稱,通常是決定那個控制器(controller)裡頭那個函數(function)要被呼叫。不過,CodeIgniter 也可以允許你用 _remap() 函數來把它來改寫成:

public function _remap()
{
    // Some code here...
}

非常重要:  如果你的控制器裡頭有個 _remap() 函數的話,那麼它會 總是 不理會你的 URI 內容是什麼東西。也就是說,這個方式會改寫掉原本函數呼叫的規則,並且允許使用你自己定義的函數路由規則(function routing rules)。

改寫函數(通常是在URI的第二個區段)將會被當成是參數傳入_remap()函數:

public function _remap($method)
{
    if ($method == 'some_method')
    {
        $this->$method();
    }
    else
    {
        $this->default_method();
    }
}

任何繼方法名稱後的區段會被當作陣列傳入 _remap() 做為第二個參數(非強制性). 此陣列與PHP原生名為 call_user_func_array 的函數相互搭配可以模擬 CodeIgniter 預設行為.

public function _remap($method, $params = array())
{
    $method = 'process_'.$method;
    if (method_exists($this, $method))
    {
        return call_user_func_array(array($this, $method), $params);
    }
    show_404();
}

輸出處理

CodeIgniter 有個 output 類別會自動處理最後給瀏覽器的資料。更多詳細的資訊可以在 檢視(Views) 以及 Output 類別 查看。某些時候,你也許會想要把最終的資料進行後續處理(post-process),然後在把處理好的資料送回給瀏覽器。CodeIgniter 可以你新增一個 _output() 到控制器裡頭,來負責接收最終的的輸出資料。

非常重要:  若你的控制器內含名為 _output() 的函數,它會 總是 被 output 類別所呼叫,而不是直接傳回最終資料。函數的第一個參數包含最終的輸出。

這裡有個參考範例:

public function _output($output)
{
    echo $output;
}

請注意, 您的 _output() 函數所接收到的資料是已完成的狀態. 也就是說資料交給_output()函數時, 效能指標跟記憶體使用量已經完成計算, 快取檔案已完成存檔 (快取啟用的情況下), 以及 headers 已經送出 (如果你有使用 該功能).

要確保你的控制器內輸出快取正常運作, 請在 _output() 的方法內加入:
if ($this->output->cache_expiration > 0)
{
    $this->output->_write_cache($output);
}
如果你使用此功能, 頁面執行的時間跟記憶體的使用量會不完全正確, 因為任何的後續動作將不會被計算在內. 另外有個方法是在任何最終計算 之前 進行輸出, 詳情請參考 Output Class.

私有函數

有時候,你會想要把某些函數隱藏起來,不讓它可以被公開存取。要把函數隱藏起來的話,只要在函數前加上個底線,然後他就不會被送給 URL 呼叫了。舉例來說,你有個像這個樣的函數:

private function _utility()
{
  // some code
}

試試看讀取像底下的 URL,應該是不會動的:

example.com/index.php/blog/_utility/

把控制器收納進子目錄裡頭

如果你正在開發大型的 application 的話,你想如果可以把一些控制器,規類到子目錄裡頭會是相當方便的。CodeIgniter 可以讓你這樣做。

只要在 application/controllers 裡頭新增子目錄,然後把你的控制器放進去即可。

注意:  如果要使用這個功能的話,URI 的第一個分段必須指定到目錄去。舉例來說,假設你有個控制器在這個:

application/controllers/products/shoes.php

你的 URL 會看起來像底下這樣,如果你去呼叫以上的控制器的話:

example.com/index.php/products/shoes/show/123

你的兩個子目錄中應該包含預設的控制器,當 URL 只有子目錄時可以被呼叫。 在 application/config/routes.php 中,可以替你的預設控制器取個你喜歡的名字。

CodeIgniter 可以讓你對映(remap)你的 URIs,只要利用 URI Routing 即可達成。

類別建構子(Class Constructors)

若打算在控制器使用建構子的話,你必須 換成底下的那行程式碼:

parent::__construct();

這一行程式碼一定需要的原因,是因為你的 local 建構子會被覆蓋成 parent 控制器類別,所以我們需要以手動方式去呼叫它

<?php
class Blog extends CI_Controller {

       public function __construct()
       {
            parent::__construct();
            // Your own constructor code
       }
}
?>

如果你的 class 是 instantiated 需要設定些預設值或是跑一些程式,建構子(Constructor)相當實用。建構子無法回傳數值,但是他們可以做一些預設工作。

保留函數名稱

自從你的控制器類別可以擴充 application controller 以來,你必須要格外小心的替你的函數命名,好讓你的類別呼叫使用,否則會發生你的 local 函數把別的函數被覆蓋掉的情況。請看保留字 的列表。

說完了!

這些就是控制器(controllers)最核心的部份。