天天看點

CI架構3.X淺析

CodeIgniter架構(簡稱CI),CI目前的穩定版本是 3.X,4.0版本已經出來了,但新出的版本畢竟有點不穩定,是以我分析的還是 3.x 版本。

CI是一個很輕便的架構,整個下載下傳包也就2M多,而且使用起來友善快捷,适用于一些簡單的功能開發,以及做app 接口。

CI架構的優點就是:輕便、操作性強、各個子產品更改起來極為友善,也是大多數人喜歡它的原因之一,沒有别的架構那麼多條條框框,當然減少束縛的同時,也意味着自己要多做一些基礎類庫的建設,基于這一點考慮:CI架構也提供了引入其他類庫方法;也就是說基礎類庫可以自己寫,也可以引入市面上的類庫。以滿足大多數企業或個人使用。

    該架構整個流程圖如下:

CI架構3.X淺析
  1. index.php 檔案作為前端控制器,初始化運作 CodeIgniter 所需的基本資源;
  2. Router 檢查 HTTP 請求,以确定如何處理該請求;
  3. 如果存在緩存檔案,将直接輸出到浏覽器,不用走下面正常的系統流程;
  4. 在加載應用程式控制器之前,對 HTTP 請求以及任何使用者送出的資料進行安全檢查;
  5. 控制器加載模型、核心類庫、輔助函數以及其他所有處理請求所需的資源;
  6. 最後一步,渲染視圖并發送至浏覽器,如果開啟了緩存,視圖被會先緩存起來用于 後續的請求。

下載下傳架構源碼,解壓得到如下代碼結構:

CI架構3.X淺析

主要有三個目錄

1、application目錄:用于開發者編寫相應的配置以及邏輯處理,開發者隻需在這個目錄下添加自己需要的開發檔案。

2、system目錄:架構的系統庫,裡面包括核心庫,類庫,輔助類庫,資料庫等,這些檔案,開發者最好不要擅自修改,它是整個架構的龍脈。

3、user_guide:使用者手冊。

接下來看看源碼的請求流程:

CI架構3.X淺析

首先假設有一個 URL 請求,入口就是 index.php,該檔案定義了幾個常量,應用的路徑,以及核心庫的路徑等。

接着引入 核心庫system/core下的 CodeIgniter.php檔案,該檔案初始化核心庫system/core裡的類庫,分别是:

{

● benchmark: "Benchmark",

● hooks: "Hooks",

● config: "Config",

● log: "Log",

● utf8: "Utf8",

● uri: "URI",

● router: "Router",

● output: "Output",

● security: "Security",

● input: "Input",

● lang: "Lang",

● loader: "Loader"

}

每個類庫的注釋在上圖已有解釋。

     同時也加載 應用項目 application/config目錄下的配置檔案(這些配置檔案都是開發者根據自己的需要去添加與配置),

根據判斷加載字元串處理庫mbstring,添加錯誤異常預處理方法。在加載的同時,也把鈎子部署到了相應位置,如果開發者定義了相應鈎子實作方法,就會在相應的位置執行。

    在 CodeIgniter.php 初始化核心庫的時候定義了五個鈎子,分别如下:

  • pre_system 在系統執行的早期調用,這個時候隻有 基準測試類 和 鈎子類 被加載了, 還沒有執行到路由或其他的流程。
  • pre_controller 在你的控制器調用之前執行,所有的基礎類都已加載,路由和安全檢查也已經完成。
  • post_controller_constructor 在你的控制器執行個體化之後立即執行,控制器的任何方法都還尚未調用。
  • post_controller 在你的控制器完全運作結束時執行。
  • post_system 在最終的頁面發送到浏覽器之後、在系統的最後期被調用。

然後,執行個體化 CI_Controller 類:

function &get_instance()

{

      return CI_Controller::get_instance();

}

通過路由 router 及 uri 得到請求的 controller控制器、method方法 以及參數,執行該方法。

期間根據開發者在application/config目錄下的配置,會加載相應的 librays 類庫、 helper輔助函數 及 DB 庫。

如果你喜歡MVC的開發模式,也可以添加model類,然後加載 model 模型類,處理相應的業務邏輯。

最後在自己定義的controller控制器處理好的資料結果渲染在html 頁面上,展示給使用者。

下面看一下CI架構幾個重要部分:

控制器

    開發者在 application/controller 目錄下添加自己的controller 控制器,但是每個控制器都要繼承核心庫裡的基類 CI_Controller,它已擷取到整個架構的核心類庫對象,通過它基本可以調用CI架構下的核心方法。

模型

     模型就是專門用來和資料庫打交道的 PHP 類,開發者在 application/models 目錄下定義自己的模型類,都要繼承 模型基類 CI_Mode。當你在控制下調用模型,隻需要下面一行代碼就執行個體化了:

$this->load->model('model_name');

輔助函數

當然開發者也可以建立自己的輔助類,檔案存放在 application/helpers 目錄下,調用的方式與系統

的輔助類一緻。

$this->load 就是 Loader.php 檔案CI_Load 類執行個體, 我們來看看 CI_Load 類下的 helper() 函數:

/**

* Helper Loader

*

* @param string|string[] $helpers Helper name(s)

* @return object

*/

public function helper($helpers = array())

{

is_array($helpers) OR $helpers = array($helpers);

foreach ($helpers as &$helper)

{

$filename = basename($helper);

$filepath = ($filename === $helper) ? '' : substr($helper, 0, strlen($helper) - strlen($filename));

$filename = strtolower(preg_replace('#(_helper)?(\.php)?$#i', '', $filename)).'_helper';

$helper = $filepath.$filename;

if (isset($this->_ci_helpers[$helper]))

{

continue;

}

// Is this a helper extension request?

$ext_helper = config_item('subclass_prefix').$filename;

$ext_loaded = FALSE;

foreach ($this->_ci_helper_paths as $path)

{

if (file_exists($path.'helpers/'.$ext_helper.'.php'))

{

include_once($path.'helpers/'.$ext_helper.'.php');

$ext_loaded = TRUE;

}

}

// If we have loaded extensions - check if the base one is here

if ($ext_loaded === TRUE)

{

$base_helper = BASEPATH.'helpers/'.$helper.'.php';

if ( ! file_exists($base_helper))

{

show_error('Unable to load the requested file: helpers/'.$helper.'.php');

}

include_once($base_helper);

$this->_ci_helpers[$helper] = TRUE;

log_message('info', 'Helper loaded: '.$helper);

continue;

}

// No extensions found ... try loading regular helpers and/or overrides

foreach ($this->_ci_helper_paths as $path)

{

if (file_exists($path.'helpers/'.$helper.'.php'))

{

include_once($path.'helpers/'.$helper.'.php');

$this->_ci_helpers[$helper] = TRUE;

log_message('info', 'Helper loaded: '.$helper);

break;

}

}

// unable to load the helper

if ( ! isset($this->_ci_helpers[$helper]))

{

show_error('Unable to load the requested file: helpers/'.$helper.'.php');

}

}

return $this;

}

     這段代碼主要是 加載(include_once) system/helpers 與 appliation/helpers 目錄下的 $name_helper.php 名稱檔案,自定義的輔助函數檔案需要添加 字首 來與 系統的輔助函數區分開。當執行完加載函數,就能得到 $this->name 執行個體,然後調用它裡面的函數。

所有輔助函數如下:

  • ​​數組輔助函數​​
  • ​​驗證碼輔助函數​​
  • ​​Cookie 輔助函數​​
  • ​​日期輔助函數​​
  • ​​目錄輔助函數​​
  • ​​下載下傳輔助函數​​
  • ​​郵件輔助函數​​
  • ​​檔案輔助函數​​
  • ​​表單輔助函數​​
  • ​​HTML 輔助函數​​
  • ​​Inflector 輔助函數​​
  • ​​語言輔助函數​​
  • ​​數字輔助函數​​
  • ​​路徑輔助函數​​
  • ​​安全輔助函數​​
  • ​​表情輔助函數​​
  • ​​字元串輔助函數​​
  • ​​文本輔助函數​​
  • ​​排版輔助函數​​
  • ​​URL 輔助函數​​
  • ​​XML 輔助函數​​

CI 類庫

所有的系統類庫都位于 system/libraries/ 目錄下,大多數情況下,在使用之前, 你要先在控制器中初始化它,使用下面的方法:

$this->load->library('class_name');

'class_name' 是你想要調用的類庫名稱,例如,要加載 表單驗證類庫,你可以這樣做:

$this->load->library('form_validation');

一旦類庫被載入,你就可以根據該類庫的使用者指南中介紹的方法去使用它了,這個類似于輔助函數。

同樣拓展自己的類庫也是在application/libraries 目錄下。

一旦加載,你就可以使用小寫字母名稱來通路你的類,調用方法:

$this->someclass->some_method();

所有的類庫如下:

  • ​​基準測試類​​
  • ​​緩存驅動器​​
  • ​​月曆類​​
  • ​​購物車類​​
  • ​​配置類​​
  • ​​Email 類​​
  • ​​加密類​​
  • ​​加密類(新版)​​
  • ​​檔案上傳類​​
  • ​​表單驗證類​​
  • ​​FTP 類​​
  • ​​圖像處理類​​
  • ​​輸入類​​
  • ​​Javascript 類​​
  • ​​語言類​​
  • ​​加載器類​​
  • ​​遷移類​​
  • ​​輸出類​​
  • ​​分頁類​​
  • ​​模闆解析類​​
  • ​​安全類​​
  • ​​Session 類​​
  • ​​HTML 表格類​​
  • ​​引用通告類​​
  • ​​排版類​​
  • ​​單元測試類​​
  • ​​URI 類​​
  • ​​使用者代理類​​
  • ​​XML-RPC 與 XML-RPC 伺服器類​​
  • ​​Zip 編碼類​​

資料庫

     CI架構封裝了多種資料庫驅動與連接配接方法,讓你輕松配置就能連接配接上,且封裝了一些查詢構造器與生成查詢結果,讓代碼看起來友善簡潔。

你隻需 在application/config/database.php 檔案下配置你連結的參數:

$db['default'] = array(

'dsn' => '',

'hostname' => 'localhost',

'username' => '',

'password' => '',

'database' => '',

'dbdriver' => 'mysqli',

'dbprefix' => '',

'pconnect' => FALSE,

'db_debug' => (ENVIRONMENT !== 'production'),

'cache_on' => FALSE,

'cachedir' => '',

'char_set' => 'utf8',

'dbcollat' => 'utf8_general_ci',

'swap_pre' => '',

'encrypt' => FALSE,

'compress' => FALSE,

'stricton' => FALSE,

'failover' => array(),

'save_queries' => TRUE

);

然後在 Controller 裡調用一句 :$this->load->database(); 就能連接配接上資料庫。

接着,你可以查詢你想要的結果:

$this->db->where('name',$name);

$query=$this->db->get('mytable',10,20);

// Executes: SELECT * FROM mytable where name=$nameLIMIT 20, 10

CI架構也提供了資料庫的事務處理,如:

$this->db->trans_start();

$this->db->query('AN SQL QUERY...');

$this->db->query('ANOTHER QUERY...');

$this->db->query('AND YET ANOTHER QUERY...');

$this->db->trans_complete();

提供了簡單的查詢緩存:

将查詢結果對象會被序列化并儲存到伺服器上的一個文本檔案中。 當下次再通路該頁面時,會直接使用緩存檔案而不用通路資料庫了。隻有讀類型(SELECT)的查詢可以被緩存。 這個相對應 Java 的hibernate 資料庫映射 就弱化了很多,Java提供了三級的緩存方式,而且在查詢資料庫的時候,并不會每次都斷開,再連接配接。

以上都是CI架構提供的重要組成部分,也許它可能滿足不了你所有的需求,但也提供了一些給你拓展的方式,如在application/core目錄下添加你的核心類,這都是CI架構已考慮到的問題。當然它在處理一些繁雜的業務邏輯的時候,還是比較薄弱的,比如說權限使用,子產品靈活增删等。

CI架構主要是以輕便,快捷上手為主要的優勢,讓你去處理一些簡單的項目。它介于一個沒有架構與一個比較笨重的架構之間,是以一個架構好不好用,還要基于你的需求。

CI架構還提供了一些其它便捷的開發幫助,它有有自己的模闆引擎,也有程式分析:

你可以在你的 控制器 方法的任何位置添加一行下面的代碼:

$this->output->enable_profiler(TRUE);

設定基準測試點

$this->benchmark->mark('code_start');// Some code happens here

$this->benchmark->mark('code_end');

echo $this->benchmark->elapsed_time('code_start','code_end');

最後輸出分析的資訊:

$sections=array('config'=>TRUE,'queries'=>TRUE);

$this->output->set_profiler_sections($sections);

下表列出了可用的分析器字段和用來通路這些字段的 key :

Key Description Default
benchmarks 在各個計時點花費的時間以及總時間 TRUE
config CodeIgniter 配置變量 TRUE
controller_info 被請求的控制器類和調用的方法 TRUE
get 請求中的所有 GET 資料 TRUE
http_headers 本次請求的 HTTP 頭部 TRUE
memory_usage 本次請求消耗的記憶體(機關位元組) TRUE
post 請求中的所有 POST 資料 TRUE
queries 列出所有執行的資料庫查詢,以及執行時間 TRUE
uri_string 本次請求的 URI TRUE
session_data 目前會話中存儲的資料 TRUE
query_toggle_count 指定顯示多少個資料庫查詢,剩下的則預設折疊起來 25