程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP CodeIgniter框架的工作原理研究

PHP CodeIgniter框架的工作原理研究

編輯:關於PHP編程

     這篇文章主要介紹了PHP CodeIgniter框架的工作原理研究,本文首先分析了它的工作流程,然後總結了它的工作原理,需要的朋友可以參考下

       

    CodeIgniter(以下簡稱CI,官網以及中國站)是一個流行的PHP框架,小巧但功能強大,簡潔輕量同時擁有很好的擴展性,在國內也比較受歡迎。另一方面,CI卻沒有與時俱進,並不支持PHP5.3之後的一些特性,導致它相對更適合較老一些的項目。雖然如此,CI仍是一個優秀的框架,而且它本身內核較小,源碼優雅,適於學習。

    CI易於使用,可以方便的開發出web應用。先來看一下CI的工作流程圖(此處內容引用自http://codeigniter.org.cn/user_guide/overview/appflow.html)


    PHP CodeIgniter框架的工作原理研究   三聯
    1.index.php 作為前端控制器,初始化運行 CodeIgniter 所需要的基本資源。
    2.Router 檢查 HTTP 請求,以確定誰來處理請求。
    3.如果緩存(Cache)文件存在,它將繞過通常的系統執行順序,被直接發送給浏覽器。
    4.安全(Security)。應用程序控制器(Application Controller)裝載之前,HTTP 請求和任何用戶提交的數據將被過濾。
    5.控制器(Controller)裝載模型、核心庫、輔助函數,以及任何處理特定請求所需的其它資源。
    6.最終視圖(View)渲染發送到 Web 浏覽器中的內容。如果開啟緩存(Caching),視圖首先被緩存,所以將可用於以後的請求。

    以上給出了一個大致流程。那麼當看到頁面在浏覽器中呈現時,程序內部究竟是如何工作的呢?
    下面按照執行順序,依次列出了CI框架主要加載的文件,並簡要介紹其作用:

    01. index.php
    定義使用環境(ENVIRONMENT),框架路徑(system_path,BASEPATH),應用目錄(application_folder),應用路徑(APPPATH)等,加載(require)CI核心文件
    02. BASEPATH/core/CodeIgniter.php (ps.實際上BASEPATH包含最後的文件分隔符'/',這裡額外加上了'/'是為了更清晰的展示)
    系統初始化文件,整個框架最核心的部分,在此加載(load)了一系列的base class,並且執行這次請求
    03. BASEPATH/core/Common.php
    common文件包含一系列的基礎和公共函數 ,供全局使用,例如load_class(),get_config()等
    04. BASEPATH/core/Benchmark
    這是一個基准測試類,默認標注了應用各個階段的執行點,以得到其執行時間。也允許你自己定義監測點。
    05. BASEPATH/core/Hooks.php
    CI_Hooks是一個鉤子類,是框架進行擴展的核心,能夠在程序允許的各個階段插入掛鉤點,執行你自定義的類,函數等
    06. BASEPATH/core/Config.php
    配置文件管理類,加載讀取或設置配置
    07. BASEPATH/core/URI.php, BASEPATH/core/Router.php
    URI類幫助你解析請求的uri,並提供分割uri的函數集合,供Router類使用
    08. BASEPATH/core/Router.php
    路由類,即通過請求的uri,和用戶配置的路由(APPPATH/config/routes.php),將用戶請求分發到指定的處理函數中(通常來說是某一個Controller實例中某一action函數)
    09. BASEPATH/core/Output.php, BASEPATH/core/Input.php
    輸入類,即處理請求的輸入參數,提供安全的獲取方式。輸出類將最後的執行結果發送出去,它還負責緩存的功能
    10. BASEPATH/core/Controller.php
    控制器基類,用單例模式對外提供實例,整個應用程序的心髒。它是一個Super Object,在應用內加載的類都可以成為控制器的成員變量,這一點非常重要,會在之後繼續 講到。
    11. APPPATH/controllers/$RTR->fetch_directory().$RTR->fetch_class().'.php'
    通過路由功能,得到控制器名,實例化真正的控制器類(子類)
    12. BASEPATH/core/Loader.php
    CI_Loader用於加載應用程序中的各種類庫,模型,視圖,數據庫,文件等,並設置成為控制器的成員變量
    13. call_user_func_array 調用處理函數
    通過路由,得到action函數名,調用 Controller->action()函數,處理應用邏輯,實際業務處理邏輯便是在action函數中寫的
    14. $OUT->_display() 將內容輸出

    以上便是整個應用程序最基礎的處理流程。下面選取核心內容代碼再進行說明,以加強對CI的理解:

    ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 <?php //*BASEPATH/system/core/Common.php //引導文件中Benchmark,Hooks,Config等都是通過這個函數進行加載的 function &load_class($class, $directory = 'libraries', $prefix = 'CI_') { //記錄加載過的類 static $_classes = array();   // 已經加載過,直接讀取並返回 if (isset($_classes[$class])) { return $_classes[$class]; }   $name = FALSE;   // 在指定目錄尋找要加載的類 foreach (array(APPPATH, BASEPATH) as $path) { if (file_exists($path.$directory.'/'.$class.'.php')) { $name = $prefix.$class;   if (class_exists($name) === FALSE) { require($path.$directory.'/'.$class.'.php'); }   break; } }   // 沒有找到 if ($name === FALSE) { exit('Unable to locate the specified class: '.$class.'.php'); }   // 追蹤記錄下剛才加載的類,is_loaded()函數在下面 is_loaded($class);   $_classes[$class] = new $name(); return $_classes[$class]; } // 記錄已經加載過的類。函數返回所有加載過的類 function &is_loaded($class = '') { static $_is_loaded = array();   if ($class != '') { $_is_loaded[strtolower($class)] = $class; }   return $_is_loaded; }   //*BASEPATH/system/core/Controller.php class CI_Controller {   private static $instance;   public function __construct() { self::$instance =& $this;   //將所有在引導文件中(CodeIgniter.php)初始化的類對象(即剛才4,5,6,7,8,9等步驟), //注冊成為控制器類的成員變量,就使得這個控制器成為一個超級對象(super object) foreach (is_loaded() as $var => $class) { $this->$var =& load_class($class); } <span style="white-space:pre"> </span>//加載Loader對象,再利用Loader對象對程序內一系列資源進行加載<span style="white-space:pre"> </span> $this->load =& load_class('Loader', 'core');   $this->load->initialize();   log_message('debug', "Controller Class Initialized"); }   //這個函數對外提供了控制器的單一實例 public static function &get_instance() { return self::$instance; } }     //*BASEPATH/system/core/CodeIgniter.php // Load the base controller class require BASEPATH.'core/Controller.php';   //通過這個全局函數就得到了控制器的實例,得到了這個超級對象, //意味著在程序其他地方調用這個函數,就能得到整個框架的控制權 function &get_instance() { return CI_Controller::get_instance(); }   // 加載對應的控制器類 // 注意:Router類會自動使用 router->_validate_request() 驗證控制器路徑 if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php')) { show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.'); }   include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php');   $class = $RTR->fetch_class(); //Controller class name $method = $RTR->fetch_method(); //action name   //.....   // 調用請求的函數 // uri中除了class/function之外的段也會被傳遞給調用的函數 call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2));   //輸出最終的內容到浏覽器 if ($EXT->_call_hook('display_override') === FALSE) { $OUT->_display(); }     //*BASEPATH/system/core/Loader.php //看一個Loader類加載model的例子。這裡只列出了部分代碼 public function model($model, $name = '', $db_conn = FALSE) { $CI =& get_instance(); if (isset($CI->$name)) { show_error('The model name you are loading is the name of a resource that is already being used: '.$name); }   $model = strtolower($model);   //依次根據model類的path進行匹配,如果找到了就加載 foreach ($this->_ci_model_paths as $mod_path) { if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) { continue; }   if ($db_conn !== FALSE AND ! class_exists('CI_DB')) { if ($db_conn === TRUE) { $db_conn = ''; }   $CI->load->database($db_conn, FALSE, TRUE); }   if ( ! class_exists('CI_Model')) { load_class('Model', 'core'); }   require_once($mod_path.'models/'.$path.$model.'.php');   $model = ucfirst($model);   //這裡依然將model對象注冊成控制器類的成員變量。Loader在加載其他資源的時候也會這麼做 $CI->$name = new $model();   $this->_ci_models[] = $name; return; }   // couldn't find the model show_error('Unable to locate the model you have specified: '.$model); }   //*BASEPATH/system/core/Model.php //__get()是一個魔術方法,當讀取一個未定義的變量的值時就會被調用 //如下是Model基類對__get()函數的一個實現,使得在Model類內,可以像直接在控制器類內一樣(例如$this->var的方式)去讀取它的變量 function __get($key) { $CI =& get_instance(); return $CI->$key; 
    1. 上一頁:
    2. 下一頁:
    Copyright © 程式師世界 All Rights Reserved