CI框架源碼解析一之入口文件index.php

    轉摘原文:原文


Index.php作爲CI框架的入口文件,源碼分析,自然而然由此開始。在源碼分析的過程中,我們並不會逐行進行解釋,而只解釋核心的功能和實現,如果英文水平很好的話,讀過index.php文件的英文註釋之後也就基本明白了inde.php都做了些什麼。本來想第一篇寫解析CI框架的目錄結構的,像這一般網上一搜都是一大堆,也就放棄了這個想法。博主是基於CodeIgniter-v3.1.0最新版本進行解讀分析。ok,書歸正傳,在博主看來CI框架的index.php文件一共完成了四項工作:

① 設置框架應用的環境狀態

② 配置系統、應用、視圖等程序目錄以及得到其路徑

③ 系統、應用、視圖等目錄的正確性驗證

④ 載入 core/CodeIgniter.php框架核心文件,啓動框架

1、設置框架應用的環境狀態

  1. define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');  

        這裏的development可以是任何你喜歡的環境名稱(比如working,再如debug),相對應的,你要在下面的switch case代碼塊中,對設定的環境做相關的錯誤等級控制。(CI框架設置了三種應用場景狀態,分別是:development(開發),testing(測試),production(產品)。development(開發)狀態,也就是默認的狀態下會產生錯誤報告,testing(測試),production(產品)狀態下則不會產生錯誤報告)否則,CI框架會認爲你沒有配置好相應的環境,從而退出進程並給出對應的錯誤信息:

  1. default:  
  2.     //header() 被用來發送自定義的 HTTP 報文。關於HTTP報文的更多信息請參考php手冊  
  3.     header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);  
  4.     echo 'The application environment is not set correctly.';  
  5.     exit(1);   

        之所以一定要配置配置ENVIRONMENT?這是因爲,CI框架中很多組件都依賴於ENVIRONMENT的配置,例如,查看system/config/Common.php, 這其中有一段引入配置文件的代碼,是這樣實現的:

  1. if (file_exists(APPPATH . 'config/' . ENVIRONMENT . '/mimes.php')) {  
  2.     $_mimes = include(APPPATH . 'config/' . ENVIRONMENT . '/mimes.php');  
  3. elseif (file_exists(APPPATH . 'config/mimes.php')) {  
  4.     $_mimes = include(APPPATH . 'config/mimes.php');  
  5. else {  
  6.     $_mimes = array();  
  7. }  

        在CI框架中,很多配置文件都是通過這種方式引入的,因此ENVRIONMENT對於CI框架的正確運行時必須的,所以需要在開始的時候配置好ENVIRONMENT。設置ENVIRONMENT的一個好處是:可以很方便的切換系統的配置而不必修改系統代碼。例如,在系統進入測試階段時,database配置爲測試的數據庫,而在系統測試完畢時,database切換到線上的數據庫。這好比是用一個開關控制了系統的環境切換,自然是非常方便的。

2、配置系統、應用、視圖等程序目錄以及得到其路徑

        CI框架允許你將系統核心源碼和應用程序代碼進行分開放置,但是你必須設定好系統的system文件夾和application文件夾(同樣,文件夾名字可以是任何合法的文件夾名稱,而不一定使用’system’和’application’)的名稱、路徑等信息:

  1. //定義系統目錄名稱  
  2. $system_path = 'system';  
  3.   
  4. //定義你的應用目錄名稱  
  5. $application_folder = 'application';  
  6.   
  7. //視圖文件存放目錄  
  8. //如果要將視圖目錄移到應用程序目錄,則設置在此處的路徑。如果空白,它將默認爲您的應用程序目錄中的標準位置。  
  9. $view_folder = '';  

        下面有這樣一段代碼,然後很多人就不明白爲什麼要放這樣幾句代碼了,在這裏特別說明一下:

  1. if (defined('STDIN')) {  
  2.     //chdir函數用來改變目錄  
  3.     chdir(dirname(__FILE__));  
  4. }  

        這段代碼主要是用來幹嘛的呢?首先,STDIN、STDOUT、STDERR是PHP以 CLI(Command Line Interface)模式運行而定義的三個常量,這三個常量類似於Shell的stdin,stdout,stdout,分別是PHP CLI模式下的標準輸入、標準輸出和標準錯誤流。也就是說,這三行代碼是爲了保證命令行模式下,CI框架可以正常運行。

3、系統、應用、視圖等目錄的正確性驗證

1) 系統(system)文件目錄的正確性驗證

  1. //得到規範化的絕對路徑名  
  2. //此段代碼用於判斷生成system系統文件目錄  
  3. if (($_temp = realpath($system_path)) !== FALSE) {  
  4.     //$system_path就是當前你的CI框架核心文件所存放的絕對路徑名  
  5.     $system_path = $_temp . DIRECTORY_SEPARATOR;  
  6. else {  
  7.     $system_path = strtr(rtrim($system_path'/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;  
  8. }  
  9.   
  10. //如果$system_path所指向的文件目錄不存在,則die  
  11. if (!is_dir($system_path)) {  
  12.     header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);  
  13.     echo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: ' . pathinfo(__FILE__, PATHINFO_BASENAME);  
  14.     exit(3); // EXIT_CONFIG  
  15. }  

2) 應用(application)文件目錄的正確性驗證

  1. //此段代碼用於判斷生成application應用文件目錄  
  2. if (is_dir($application_folder)) {  
  3.     if (($_temp = realpath($application_folder)) !== FALSE) {  
  4.         $application_folder = $_temp;  
  5.     } else {  
  6.         $application_folder = strtr(rtrim($application_folder'/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);  
  7.     }  
  8. elseif (is_dir(BASEPATH . $application_folder . DIRECTORY_SEPARATOR)) {  
  9.     $application_folder = BASEPATH . strtr(trim($application_folder'/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);  
  10. else {  
  11.     header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);  
  12.     echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: ' . SELF;  
  13.     exit(3);  
  14. }  

3) 視圖(view)文件目錄的正確性驗證

  1. //此段代碼用於判斷生成view視圖文件目錄  
  2. if (!isset($view_folder[0]) && is_dir(APPPATH . 'views' . DIRECTORY_SEPARATOR)) {  
  3.     $view_folder = APPPATH . 'views';  
  4. elseif (is_dir($view_folder)) {  
  5.     if (($_temp = realpath($view_folder)) !== FALSE) {  
  6.         $view_folder = $_temp;  
  7.     } else {  
  8.         $view_folder = strtr(rtrim($view_folder'/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);  
  9.     }  
  10. elseif (is_dir(APPPATH . $view_folder . DIRECTORY_SEPARATOR)) {  
  11.     $view_folder = APPPATH . strtr(trim($view_folder'/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);  
  12. else {  
  13.     header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);  
  14.     echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: ' . SELF;  
  15.     exit(3);  
  16. }  

        幾個定義的常量(PATH結尾的常量表示目錄路徑,DIR結尾的變量表示目錄名):

  1. //SELF(這裏指index.php文件)  
  2. define('SELF'pathinfo(__FILE__, PATHINFO_BASENAME));  
  3. //BASEPATH(system文件夾的路徑)  
  4. define('BASEPATH'$system_path);  
  5. //FCPATH(前端控制器的路徑)  
  6. define('FCPATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);  
  7. //SYSDIR(系統system目錄名)  
  8. define('SYSDIR'basename(BASEPATH));  
  9. //APPPATH(應用程序路徑)  
  10. define('APPPATH'$application_folder . DIRECTORY_SEPARATOR);  
  11. //VIEWPATH(視圖目錄路徑)  
  12. define('VIEWPATH'$view_folder . DIRECTORY_SEPARATOR);  

       注:查看所有常量的方法:

  1. var_dump(get_defined_constants());  

4、載入 core/CodeIgniter.php框架核心文件,啓動框架

       入口文件的最後一行,引入CodeIgniter.php框架核心文件(也是下一步框架執行的關鍵)。CodeIgniter.php被稱爲bootstrap file,也就是它是一個引導文件,是CI框架執行流程的核心文件。

  1. //最後就是加載CI框架的核心引導文件了  
  2. require_once BASEPATH . 'core/CodeIgniter.php';  

        總結一下,index.php並沒有做太多複雜的工作,而是類似軍隊中押運糧草的,兵馬未動糧草先行,爲CI框架的運行提供了一系列配置參數和正確性驗證,而這些配置和驗證,是CI框架能夠正常運行的關鍵。

        最後,貼一下整個index.php文件的源碼(註釋版):

  1. <?php  
  2.   
  3. /** 
  4.  * ======================================= 
  5.  * Created by Pocket Knife Technology. 
  6.  * User: ZhiHua_W 
  7.  * Date: 2016/10/14 0020 
  8.  * Time: 下午 2:14 
  9.  * Project: CodeIgniter框架—源碼分析 
  10.  * Power: Analysis for Index.php 
  11.  * ======================================= 
  12.  */  
  13.   
  14. /** 
  15.  * 框架的第一步就是定義框架代碼當前的使用場景狀態 
  16.  * 一共有development(開發),testing(測試),production(產品)三個場景狀態 
  17.  * 不同的場景狀態將會產生不同級別的錯誤報告 
  18.  */  
  19. define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');  
  20.   
  21. /** 
  22.  * 這裏就會對場景狀態進行判斷 
  23.  * development(開發)狀態,也就是默認的狀態下會產生錯誤報告 
  24.  * testing(測試),production(產品)狀態下則不會產生錯誤報告 
  25.  */  
  26. switch (ENVIRONMENT) {  
  27.     case 'development':  
  28.         //error_reporting()函數是php的內置函數,用來設置php的報錯級別並返回當前級別  
  29.         //函數語法:  
  30.         //error_reporting(report_level) report_level參數是錯誤等級,一共有已下幾種:  
  31.         //值 常量 描述  
  32.         //1 E_ERROR 致命的運行錯誤。錯誤無法恢復,暫停執行腳本  
  33.         //2 E_WARNING 運行時警告(非致命性錯誤)。非致命的運行錯誤,腳本執行不會停止  
  34.         //4 E_PARSE 編譯時解析錯誤。解析錯誤只由分析器產生  
  35.         //8 E_NOTICE 運行時提醒(這些經常是你代碼中的bug引起的,也可能是有意的行爲造成的。)  
  36.         //16 E_CORE_ERROR PHP啓動時初始化過程中的致命錯誤  
  37.         //32 E_CORE_WARNING PHP啓動時初始化過程中的警告(非致命性錯)。  
  38.         //64 E_COMPILE_ERROR 編譯時致命性錯。這就像由Zend腳本引擎生成了一個E_ERROR  
  39.         ///128 E_COMPILE_WARNING 編譯時警告(非致命性錯)。這就像由Zend腳本引擎生成了一個E_WARNING警告  
  40.         //256 E_USER_ERROR 用戶自定義的錯誤消息。這就像由使用PHP函數trigger_error(程序員設置E_ERROR)  
  41.         //512 E_USER_WARNING 用戶自定義的警告消息。這就像由使用PHP函數trigger_error(程序員設定的一個E_WARNING警告)  
  42.         //1024 E_USER_NOTICE 用戶自定義的提醒消息。這就像一個由使用PHP函數trigger_error(程序員一個E_NOTICE集)  
  43.         //2048 E_STRICT 編碼標準化警告。允許PHP建議如何修改代碼以確保最佳的互操作性向前兼容性  
  44.         //4096 E_RECOVERABLE_ERROR 開捕致命錯誤。這就像一個E_ERROR,但可以通過用戶定義的處理捕獲(又見set_error_handler())  
  45.         //8191 E_ALL 所有的錯誤和警告(不包括 E_STRICT) (E_STRICT will be part of E_ALL as of PHP 6.0)  
  46.         //更爲具體的用法大家可以查詢php手冊  
  47.         error_reporting(-1);  
  48.   
  49.         //ini_set用來設置php.ini的值,在函數執行的時候生效,腳本結束後,設置失效。  
  50.         //無需打開php.ini文件,就能修改配置,對於虛擬空間來說,很方便。  
  51.         //不是所有的參數都可以配置,可以查看手冊中的列表。  
  52.         //可以使用ini_get來獲取所設置的值,例如:echo ini_get('display_errors');  
  53.         ini_set('display_errors', 1);  
  54.   
  55.         break;  
  56.   
  57.     case 'testing':  
  58.     case 'production':  
  59.         ini_set('display_errors', 0);  
  60.   
  61.         //version_compare() 用於對比兩個「PHP 規範化」的版本數字字符串。 這對於編寫僅能兼容某些版本 PHP 的程序很有幫助。  
  62.         if (version_compare(PHP_VERSION, '5.3''>=')) {  
  63.             error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);  
  64.         } else {  
  65.             error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_USER_NOTICE);  
  66.         }  
  67.         break;  
  68.   
  69.     default:  
  70.         //header() 被用來發送自定義的 HTTP 報文。關於HTTP報文的更多信息請參考php手冊  
  71.         header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);  
  72.         echo 'The application environment is not set correctly.';  
  73.         exit(1); // EXIT_ERROR  
  74. }  
  75.   
  76. /** 
  77.  * 定義系統目錄名稱 
  78.  * 此變量必須包含您的“系統”目錄的名稱。如果它不在與此文件相同的目錄中,則設置路徑。 
  79.  * 裏面存放的是CI框架的各種核心文件。 
  80.  */  
  81. $system_path = 'system';  
  82.   
  83. /** 
  84.  * 定義你的應用目錄名稱 
  85.  * 如果你希望此前控制器使用不同的“應用程序”目錄,而不是默認的“應用程序”目錄,你可以在這裏設置它的名稱。 
  86.  */  
  87. $application_folder = 'application';  
  88.   
  89. /** 
  90.  * 視圖文件存放目錄 
  91.  * 如果要將視圖目錄移到應用程序目錄,則設置在此處的路徑。如果空白,它將默認爲您的應用程序目錄中的標準位置。 
  92.  */  
  93. $view_folder = '';  
  94.   
  95.   
  96. // --------------------------------------------------------------------  
  97. // END OF USER CONFIGURABLE SETTINGS.  DO NOT EDIT BELOW THIS LINE  
  98. //用戶可配置設置的結束。不要在這條線下編輯  
  99. //這裏只是CI框架進行一下提示,如果你想改動的話,還是可以的  
  100. // --------------------------------------------------------------------  
  101.   
  102.   
  103. //設置正確的目錄  
  104. /** 
  105.  * STDIN、STDOUT、STDERR是PHP以 CLI(Command Line Interface)模式運行而定義的三個常量, 
  106.  * 這三個常量類似於Shell的stdin,stdout,stdout,分別是PHP CLI模式下的標準輸入、標準輸出和標準錯誤流。 
  107.  * 也就是說,這三行代碼是爲了保證命令行模式下,CI框架可以正常運行。 
  108.  */  
  109. if (defined('STDIN')) {  
  110.     //chdir函數用來改變目錄  
  111.     chdir(dirname(__FILE__));  
  112. }  
  113. //得到規範化的絕對路徑名  
  114. //此段代碼用於判斷生成system系統文件目錄  
  115. if (($_temp = realpath($system_path)) !== FALSE) {  
  116.     //$system_path就是當前你的CI框架核心文件所存放的絕對路徑名  
  117.     $system_path = $_temp . DIRECTORY_SEPARATOR;  
  118. else {  
  119.     $system_path = strtr(  
  120.             rtrim($system_path'/\\'),  
  121.             '/\\',  
  122.             DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR  
  123.         ) . DIRECTORY_SEPARATOR;  
  124. }  
  125.   
  126. //如果$system_path所指向的文件目錄不存在,則die  
  127. if (!is_dir($system_path)) {  
  128.     header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);  
  129.     echo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: ' . pathinfo(__FILE__, PATHINFO_BASENAME);  
  130.     exit(3); // EXIT_CONFIG  
  131. }  
  132.   
  133. /** 
  134.  * 下面主要是設置各種主要的常量 
  135.  */  
  136. //當前文件名稱,也就是“index.php”  
  137. //pathinfo()函數返回文件路徑的信息  
  138. define('SELF'pathinfo(__FILE__, PATHINFO_BASENAME));  
  139.   
  140. //system文件的絕對路徑  
  141. define('BASEPATH'$system_path);  
  142.   
  143. //項目文件目錄的絕對路徑  
  144. //dirname()函數返回路徑中的目錄部分  
  145. define('FCPATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);  
  146.   
  147. // system文件夾名稱“system”  
  148. //basename()函數返回路徑中的文件名部分  
  149. define('SYSDIR'basename(BASEPATH));  
  150.   
  151. //此段代碼用於判斷生成application應用文件目錄  
  152. if (is_dir($application_folder)) {  
  153.     if (($_temp = realpath($application_folder)) !== FALSE) {  
  154.         $application_folder = $_temp;  
  155.     } else {  
  156.         $application_folder = strtr(  
  157.             rtrim($application_folder'/\\'),  
  158.             '/\\',  
  159.             DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR  
  160.         );  
  161.     }  
  162. elseif (is_dir(BASEPATH . $application_folder . DIRECTORY_SEPARATOR)) {  
  163.     $application_folder = BASEPATH . strtr(  
  164.             trim($application_folder'/\\'),  
  165.             '/\\',  
  166.             DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR  
  167.         );  
  168. else {  
  169.     header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);  
  170.     echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: ' . SELF;  
  171.     exit(3); // EXIT_CONFIG  
  172. }  
  173. //application應用目錄的絕對路徑  
  174. define('APPPATH'$application_folder . DIRECTORY_SEPARATOR);  
  175.   
  176. //此段代碼用於判斷生成view視圖文件目錄  
  177. if (!isset($view_folder[0]) && is_dir(APPPATH . 'views' . DIRECTORY_SEPARATOR)) {  
  178.     $view_folder = APPPATH . 'views';  
  179. elseif (is_dir($view_folder)) {  
  180.     if (($_temp = realpath($view_folder)) !== FALSE) {  
  181.         $view_folder = $_temp;  
  182.     } else {  
  183.         $view_folder = strtr(  
  184.             rtrim($view_folder'/\\'),  
  185.             '/\\',  
  186.             DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR  
  187.         );  
  188.     }  
  189. elseif (is_dir(APPPATH . $view_folder . DIRECTORY_SEPARATOR)) {  
  190.     $view_folder = APPPATH . strtr(  
  191.             trim($view_folder'/\\'),  
  192.             '/\\',  
  193.             DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR  
  194.         );  
  195. else {  
  196.     header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);  
  197.     echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: ' . SELF;  
  198.     exit(3); // EXIT_CONFIG  
  199. }  
  200. //view視圖目錄的絕對路徑  
  201. define('VIEWPATH'$view_folder . DIRECTORY_SEPARATOR);  
  202.   
  203. //最後就是加載CI框架的核心引導文件了  
  204. require_once BASEPATH . 'core/CodeIgniter.php';  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章