控制器(Controllers)
控制器(Controllers)是你的 application 的核心動力,決定了如何處理 HTTP 所發出的要求。
- 什麼是控制器(Controller)呢?
- 我們的第一個程式: Hello World!
- 函數(Functions)
- 傳遞 URI 段落到你的函數裡
- 定義預設的控制器
- 重新對映函數呼叫
- 控制輸出資料
- 私有函數
- 把控制器收納進子目錄裡頭
- 類別建構子(Class Constructors)
- 保留函數名稱
什麼是控制器(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)
如果你使用此功能, 頁面執行的時間跟記憶體的使用量會不完全正確, 因為任何的後續動作將不會被計算在內. 另外有個方法是在任何最終計算 之前 進行輸出, 詳情請參考 Output Class.
{
$this->output->_write_cache($output);
}
私有函數
有時候,你會想要把某些函數隱藏起來,不讓它可以被公開存取。要把函數隱藏起來的話,只要在函數前加上個底線,然後他就不會被送給 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)最核心的部份。