使用CI框架開發了一段時間,發現它容易上手,使用起來也方便,最重要是很輕便,這引起我的興趣去分析該框架的設計。這是國外開源的項目,有一段時間特別火,下麵讓我們來看看唄。 ...
業餘花了點時間看看CodeIgniter框架(簡稱CI),CI目前的穩定版本是 3.X,4.0版本已經出來了,但還在測試中,所以我分析的還是 3.x 版本。 CI是一個很輕便的框架,整個下載包也就2M多,而且使用起來方便快捷,適用於一些簡單的功能開發,以及做app 介面。 該框架整個流程圖如下:
- index.php 文件作為前端控制器,初始化運行 CodeIgniter 所需的基本資源;
- Router 檢查 HTTP 請求,以確定如何處理該請求;
- 如果存在緩存文件,將直接輸出到瀏覽器,不用走下麵正常的系統流程;
- 在載入應用程式控制器之前,對 HTTP 請求以及任何用戶提交的數據進行安全檢查;
- 控制器載入模型、核心類庫、輔助函數以及其他所有處理請求所需的資源;
- 最後一步,渲染視圖併發送至瀏覽器,如果開啟了緩存,視圖被會先緩存起來用於 後續的請求。
主要有三個目錄
1、application目錄:用於開發者編寫相應的配置以及邏輯處理,開發者只需在這個目錄下添加自己需要的開發文件。
2、system目錄:框架的系統庫,裡面包括核心庫,類庫,輔助類庫,資料庫等,這些文件,開發者最好不要擅自修改,它是整個框架的龍脈。
3、user_guide:用戶手冊。
接下來看看源碼的請求流程: 首先假設有一個 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 在最終的頁面發送到瀏覽器之後、在系統的最後期被調用。
/** * 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 輔助函數
- 基準測試類
- 緩存驅動器
- 日曆類
- 購物車類
- 配置類
- 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 |