前言
使用現有的codeigniter還不能很好地滿足我們業務的需求,比如在做一個API服務器的時候,一些權限驗證,格式輸出的事情都比較難完成,如果都單獨寫在各個controller里的話就顯得冗余不可維護。所以我們要對Codeigniter進行一些特殊的定制。
自定義控制器
原本的CI_controller是所有controller的父類,其功能是簡單的。我們還希望對于controller以及每個調用的函數都做一些統一的工作,比如權限驗證、輸入驗證、輸出格式等等。所以我們有必要自己再封裝一層controller的基類。具體描述如下:
override _remap($method, $params)
這個函數在每個controller成員函數被調用前都會被調用,參數$method表示當前被調用的函數,$params表示傳遞的參數。我們可以對這個在這個函數里面做一些目標函數被調用時候的預處理,接著調用call_user_func_array來執行真正的函數,并得到結果。override __destruct()
這個解構函數中,我們可以做一些做一些輸出格式化的工作。CI中的$this->output類是框架帶有的輸出類,我們controller控制過程中的load->view其實都是被這個類給緩存下來了,只有當調用$this->output->_display()后才會真正傳輸到瀏覽器中(默認的,_display()會自動在output析構的時候調用)。我們可以在__destruct中對輸出進行一些定制,比如對call_user_func_array的輸出封裝一些格式化的東西。步驟
step1 在application/config/config.php中,配置修改$config['subclass_prefix']一行代碼,開啟對API_自定義類的自動加載。
$config['subclass_prefix'] = 'API_';
- step2 新建application/core/API_Controller并編輯成如下內容。函數內部的內容是自定義的,這里只是舉個返回json的例子。
class API_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
$this->result = array();
}
function _remap($method, $params = array()){
$methodResult = call_user_func_array(array($this, $method), array());
$this->result['result'] = $methodResult;
return $methodResult;
}
function __destruct(){
$this->result['msg'] = 'success';
$this->output->set_content_type('json');
$this->output->set_output(json_encode($this->result));
$this->output->_display();
}
}
- step3 修改自己的業務controller繼承這個API_Controller即可。
自定義錯誤處理
服務端經常發生程序在業務上遇到邏輯錯誤的情況,比如余額不足無法購買,沒有登錄這樣的錯誤處理信息。處理錯誤返回在原來也是一個比較麻煩的事情,要寫一大堆判斷和返回錯誤碼來告訴客戶端相對應錯誤。為了解決這個錯誤處理的問題,我們用異常來解決這件事情。我們向框架統一注冊一個底層的異常處理程序,這樣在業務處理錯誤的時候,任何地方都可以threw一個異常。底層異常處理程序捕獲異常之后,根據異常取出相關的信息,統一處理或者封裝之后返回給客戶端,就解決了這個令人頭疼的錯誤處理。
- _exception_handler
原來框架有定義了錯誤處理,在system\core\CodeIgniter.php中有如下的描述。
set_error_handler('_error_handler');
set_exception_handler('_exception_handler');
register_shutdown_function('_shutdown_handler');
分別表示發送運行錯誤的時候用_error_handler函數來處理,發生未捕獲的異常的時候用_exception_handler來處理,showdown的時候用_shutdown_handler處理。這三個函數都在system\core\Common.php被定義。
理論上我們修改Common.php中這三個函數的內容就行了。但是原則上我們不應該去修改system目錄下的文件。所以我們換一種方式,只要搶先聲明_exception_handler就可以override這個異常處理了,其他幾個函數要定制的話也是同理。
我們發現applicaiton下有個constants.php的文件是在Common.php的文件前被引入的,所以自然地我們在constants.php中做一些手腳。
- 步驟
step1 新建文件application\core\exception\exception_handler.php,編輯如下
<?php
if(!function_exists('_exception_handler')){
function _exception_handler($exception){
$_error =& load_class('Exceptions', 'core');
$_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getLine());
// Should we display the error?
if(true){
$statusCode = method_exists($exception, 'getStatusCode')?$exception->getStatusCode():500;
set_status_header($statusCode);
!class_exists('CI_Controller') OR $ci = get_instance();
$ci->result['err'] = $statusCode;
}
exit(1); // EXIT_ERROR
}
}
step2 在application\config\constants.php文件末尾添加上
require_once (APPPATH.'core/exception/exception_handler.php');
這樣就完成了復寫_exception_handler的工作。一些基礎的自定義Exception類也可以放在application\core\exception\目錄下