轉摘原文:原文
Index.php作爲CI框架的入口文件,源碼分析,自然而然由此開始。在源碼分析的過程中,我們並不會逐行進行解釋,而只解釋核心的功能和實現,如果英文水平很好的話,讀過index.php文件的英文註釋之後也就基本明白了inde.php都做了些什麼。本來想第一篇寫解析CI框架的目錄結構的,像這一般網上一搜都是一大堆,也就放棄了這個想法。博主是基於CodeIgniter-v3.1.0最新版本進行解讀分析。ok,書歸正傳,在博主看來CI框架的index.php文件一共完成了四項工作:
① 設置框架應用的環境狀態
② 配置系統、應用、視圖等程序目錄以及得到其路徑
③ 系統、應用、視圖等目錄的正確性驗證
④ 載入 core/CodeIgniter.php框架核心文件,啓動框架
1、設置框架應用的環境狀態
- define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');
這裏的development可以是任何你喜歡的環境名稱(比如working,再如debug),相對應的,你要在下面的switch case代碼塊中,對設定的環境做相關的錯誤等級控制。(CI框架設置了三種應用場景狀態,分別是:development(開發),testing(測試),production(產品)。development(開發)狀態,也就是默認的狀態下會產生錯誤報告,testing(測試),production(產品)狀態下則不會產生錯誤報告)否則,CI框架會認爲你沒有配置好相應的環境,從而退出進程並給出對應的錯誤信息:
- default:
- //header() 被用來發送自定義的 HTTP 報文。關於HTTP報文的更多信息請參考php手冊
- header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
- echo 'The application environment is not set correctly.';
- exit(1);
之所以一定要配置配置ENVIRONMENT?這是因爲,CI框架中很多組件都依賴於ENVIRONMENT的配置,例如,查看system/config/Common.php, 這其中有一段引入配置文件的代碼,是這樣實現的:
- if (file_exists(APPPATH . 'config/' . ENVIRONMENT . '/mimes.php')) {
- $_mimes = include(APPPATH . 'config/' . ENVIRONMENT . '/mimes.php');
- } elseif (file_exists(APPPATH . 'config/mimes.php')) {
- $_mimes = include(APPPATH . 'config/mimes.php');
- } else {
- $_mimes = array();
- }
在CI框架中,很多配置文件都是通過這種方式引入的,因此ENVRIONMENT對於CI框架的正確運行時必須的,所以需要在開始的時候配置好ENVIRONMENT。設置ENVIRONMENT的一個好處是:可以很方便的切換系統的配置而不必修改系統代碼。例如,在系統進入測試階段時,database配置爲測試的數據庫,而在系統測試完畢時,database切換到線上的數據庫。這好比是用一個開關控制了系統的環境切換,自然是非常方便的。
2、配置系統、應用、視圖等程序目錄以及得到其路徑
CI框架允許你將系統核心源碼和應用程序代碼進行分開放置,但是你必須設定好系統的system文件夾和application文件夾(同樣,文件夾名字可以是任何合法的文件夾名稱,而不一定使用’system’和’application’)的名稱、路徑等信息:
- //定義系統目錄名稱
- $system_path = 'system';
- //定義你的應用目錄名稱
- $application_folder = 'application';
- //視圖文件存放目錄
- //如果要將視圖目錄移到應用程序目錄,則設置在此處的路徑。如果空白,它將默認爲您的應用程序目錄中的標準位置。
- $view_folder = '';
下面有這樣一段代碼,然後很多人就不明白爲什麼要放這樣幾句代碼了,在這裏特別說明一下:
- if (defined('STDIN')) {
- //chdir函數用來改變目錄
- chdir(dirname(__FILE__));
- }
這段代碼主要是用來幹嘛的呢?首先,STDIN、STDOUT、STDERR是PHP以 CLI(Command Line Interface)模式運行而定義的三個常量,這三個常量類似於Shell的stdin,stdout,stdout,分別是PHP CLI模式下的標準輸入、標準輸出和標準錯誤流。也就是說,這三行代碼是爲了保證命令行模式下,CI框架可以正常運行。
3、系統、應用、視圖等目錄的正確性驗證
1) 系統(system)文件目錄的正確性驗證
- //得到規範化的絕對路徑名
- //此段代碼用於判斷生成system系統文件目錄
- if (($_temp = realpath($system_path)) !== FALSE) {
- //$system_path就是當前你的CI框架核心文件所存放的絕對路徑名
- $system_path = $_temp . DIRECTORY_SEPARATOR;
- } else {
- $system_path = strtr(rtrim($system_path, '/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
- }
- //如果$system_path所指向的文件目錄不存在,則die
- if (!is_dir($system_path)) {
- header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
- echo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: ' . pathinfo(__FILE__, PATHINFO_BASENAME);
- exit(3); // EXIT_CONFIG
- }
2) 應用(application)文件目錄的正確性驗證
- //此段代碼用於判斷生成application應用文件目錄
- if (is_dir($application_folder)) {
- if (($_temp = realpath($application_folder)) !== FALSE) {
- $application_folder = $_temp;
- } else {
- $application_folder = strtr(rtrim($application_folder, '/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
- }
- } elseif (is_dir(BASEPATH . $application_folder . DIRECTORY_SEPARATOR)) {
- $application_folder = BASEPATH . strtr(trim($application_folder, '/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
- } else {
- header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
- echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: ' . SELF;
- exit(3);
- }
3) 視圖(view)文件目錄的正確性驗證
- //此段代碼用於判斷生成view視圖文件目錄
- if (!isset($view_folder[0]) && is_dir(APPPATH . 'views' . DIRECTORY_SEPARATOR)) {
- $view_folder = APPPATH . 'views';
- } elseif (is_dir($view_folder)) {
- if (($_temp = realpath($view_folder)) !== FALSE) {
- $view_folder = $_temp;
- } else {
- $view_folder = strtr(rtrim($view_folder, '/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
- }
- } elseif (is_dir(APPPATH . $view_folder . DIRECTORY_SEPARATOR)) {
- $view_folder = APPPATH . strtr(trim($view_folder, '/\\'), '/\\', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
- } else {
- header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
- echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: ' . SELF;
- exit(3);
- }
幾個定義的常量(PATH結尾的常量表示目錄路徑,DIR結尾的變量表示目錄名):
- //SELF(這裏指index.php文件)
- define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
- //BASEPATH(system文件夾的路徑)
- define('BASEPATH', $system_path);
- //FCPATH(前端控制器的路徑)
- define('FCPATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);
- //SYSDIR(系統system目錄名)
- define('SYSDIR', basename(BASEPATH));
- //APPPATH(應用程序路徑)
- define('APPPATH', $application_folder . DIRECTORY_SEPARATOR);
- //VIEWPATH(視圖目錄路徑)
- define('VIEWPATH', $view_folder . DIRECTORY_SEPARATOR);
注:查看所有常量的方法:
- var_dump(get_defined_constants());
4、載入 core/CodeIgniter.php框架核心文件,啓動框架
入口文件的最後一行,引入CodeIgniter.php框架核心文件(也是下一步框架執行的關鍵)。CodeIgniter.php被稱爲bootstrap file,也就是它是一個引導文件,是CI框架執行流程的核心文件。
- //最後就是加載CI框架的核心引導文件了
- require_once BASEPATH . 'core/CodeIgniter.php';
總結一下,index.php並沒有做太多複雜的工作,而是類似軍隊中押運糧草的,兵馬未動糧草先行,爲CI框架的運行提供了一系列配置參數和正確性驗證,而這些配置和驗證,是CI框架能夠正常運行的關鍵。
最後,貼一下整個index.php文件的源碼(註釋版):
- <?php
- /**
- * =======================================
- * Created by Pocket Knife Technology.
- * User: ZhiHua_W
- * Date: 2016/10/14 0020
- * Time: 下午 2:14
- * Project: CodeIgniter框架—源碼分析
- * Power: Analysis for Index.php
- * =======================================
- */
- /**
- * 框架的第一步就是定義框架代碼當前的使用場景狀態
- * 一共有development(開發),testing(測試),production(產品)三個場景狀態
- * 不同的場景狀態將會產生不同級別的錯誤報告
- */
- define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');
- /**
- * 這裏就會對場景狀態進行判斷
- * development(開發)狀態,也就是默認的狀態下會產生錯誤報告
- * testing(測試),production(產品)狀態下則不會產生錯誤報告
- */
- switch (ENVIRONMENT) {
- case 'development':
- //error_reporting()函數是php的內置函數,用來設置php的報錯級別並返回當前級別
- //函數語法:
- //error_reporting(report_level) report_level參數是錯誤等級,一共有已下幾種:
- //值 常量 描述
- //1 E_ERROR 致命的運行錯誤。錯誤無法恢復,暫停執行腳本
- //2 E_WARNING 運行時警告(非致命性錯誤)。非致命的運行錯誤,腳本執行不會停止
- //4 E_PARSE 編譯時解析錯誤。解析錯誤只由分析器產生
- //8 E_NOTICE 運行時提醒(這些經常是你代碼中的bug引起的,也可能是有意的行爲造成的。)
- //16 E_CORE_ERROR PHP啓動時初始化過程中的致命錯誤
- //32 E_CORE_WARNING PHP啓動時初始化過程中的警告(非致命性錯)。
- //64 E_COMPILE_ERROR 編譯時致命性錯。這就像由Zend腳本引擎生成了一個E_ERROR
- ///128 E_COMPILE_WARNING 編譯時警告(非致命性錯)。這就像由Zend腳本引擎生成了一個E_WARNING警告
- //256 E_USER_ERROR 用戶自定義的錯誤消息。這就像由使用PHP函數trigger_error(程序員設置E_ERROR)
- //512 E_USER_WARNING 用戶自定義的警告消息。這就像由使用PHP函數trigger_error(程序員設定的一個E_WARNING警告)
- //1024 E_USER_NOTICE 用戶自定義的提醒消息。這就像一個由使用PHP函數trigger_error(程序員一個E_NOTICE集)
- //2048 E_STRICT 編碼標準化警告。允許PHP建議如何修改代碼以確保最佳的互操作性向前兼容性
- //4096 E_RECOVERABLE_ERROR 開捕致命錯誤。這就像一個E_ERROR,但可以通過用戶定義的處理捕獲(又見set_error_handler())
- //8191 E_ALL 所有的錯誤和警告(不包括 E_STRICT) (E_STRICT will be part of E_ALL as of PHP 6.0)
- //更爲具體的用法大家可以查詢php手冊
- error_reporting(-1);
- //ini_set用來設置php.ini的值,在函數執行的時候生效,腳本結束後,設置失效。
- //無需打開php.ini文件,就能修改配置,對於虛擬空間來說,很方便。
- //不是所有的參數都可以配置,可以查看手冊中的列表。
- //可以使用ini_get來獲取所設置的值,例如:echo ini_get('display_errors');
- ini_set('display_errors', 1);
- break;
- case 'testing':
- case 'production':
- ini_set('display_errors', 0);
- //version_compare() 用於對比兩個「PHP 規範化」的版本數字字符串。 這對於編寫僅能兼容某些版本 PHP 的程序很有幫助。
- if (version_compare(PHP_VERSION, '5.3', '>=')) {
- error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
- } else {
- error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_USER_NOTICE);
- }
- break;
- default:
- //header() 被用來發送自定義的 HTTP 報文。關於HTTP報文的更多信息請參考php手冊
- header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
- echo 'The application environment is not set correctly.';
- exit(1); // EXIT_ERROR
- }
- /**
- * 定義系統目錄名稱
- * 此變量必須包含您的“系統”目錄的名稱。如果它不在與此文件相同的目錄中,則設置路徑。
- * 裏面存放的是CI框架的各種核心文件。
- */
- $system_path = 'system';
- /**
- * 定義你的應用目錄名稱
- * 如果你希望此前控制器使用不同的“應用程序”目錄,而不是默認的“應用程序”目錄,你可以在這裏設置它的名稱。
- */
- $application_folder = 'application';
- /**
- * 視圖文件存放目錄
- * 如果要將視圖目錄移到應用程序目錄,則設置在此處的路徑。如果空白,它將默認爲您的應用程序目錄中的標準位置。
- */
- $view_folder = '';
- // --------------------------------------------------------------------
- // END OF USER CONFIGURABLE SETTINGS. DO NOT EDIT BELOW THIS LINE
- //用戶可配置設置的結束。不要在這條線下編輯
- //這裏只是CI框架進行一下提示,如果你想改動的話,還是可以的
- // --------------------------------------------------------------------
- //設置正確的目錄
- /**
- * STDIN、STDOUT、STDERR是PHP以 CLI(Command Line Interface)模式運行而定義的三個常量,
- * 這三個常量類似於Shell的stdin,stdout,stdout,分別是PHP CLI模式下的標準輸入、標準輸出和標準錯誤流。
- * 也就是說,這三行代碼是爲了保證命令行模式下,CI框架可以正常運行。
- */
- if (defined('STDIN')) {
- //chdir函數用來改變目錄
- chdir(dirname(__FILE__));
- }
- //得到規範化的絕對路徑名
- //此段代碼用於判斷生成system系統文件目錄
- if (($_temp = realpath($system_path)) !== FALSE) {
- //$system_path就是當前你的CI框架核心文件所存放的絕對路徑名
- $system_path = $_temp . DIRECTORY_SEPARATOR;
- } else {
- $system_path = strtr(
- rtrim($system_path, '/\\'),
- '/\\',
- DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR
- ) . DIRECTORY_SEPARATOR;
- }
- //如果$system_path所指向的文件目錄不存在,則die
- if (!is_dir($system_path)) {
- header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
- echo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: ' . pathinfo(__FILE__, PATHINFO_BASENAME);
- exit(3); // EXIT_CONFIG
- }
- /**
- * 下面主要是設置各種主要的常量
- */
- //當前文件名稱,也就是“index.php”
- //pathinfo()函數返回文件路徑的信息
- define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
- //system文件的絕對路徑
- define('BASEPATH', $system_path);
- //項目文件目錄的絕對路徑
- //dirname()函數返回路徑中的目錄部分
- define('FCPATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);
- // system文件夾名稱“system”
- //basename()函數返回路徑中的文件名部分
- define('SYSDIR', basename(BASEPATH));
- //此段代碼用於判斷生成application應用文件目錄
- if (is_dir($application_folder)) {
- if (($_temp = realpath($application_folder)) !== FALSE) {
- $application_folder = $_temp;
- } else {
- $application_folder = strtr(
- rtrim($application_folder, '/\\'),
- '/\\',
- DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR
- );
- }
- } elseif (is_dir(BASEPATH . $application_folder . DIRECTORY_SEPARATOR)) {
- $application_folder = BASEPATH . strtr(
- trim($application_folder, '/\\'),
- '/\\',
- DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR
- );
- } else {
- header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
- echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: ' . SELF;
- exit(3); // EXIT_CONFIG
- }
- //application應用目錄的絕對路徑
- define('APPPATH', $application_folder . DIRECTORY_SEPARATOR);
- //此段代碼用於判斷生成view視圖文件目錄
- if (!isset($view_folder[0]) && is_dir(APPPATH . 'views' . DIRECTORY_SEPARATOR)) {
- $view_folder = APPPATH . 'views';
- } elseif (is_dir($view_folder)) {
- if (($_temp = realpath($view_folder)) !== FALSE) {
- $view_folder = $_temp;
- } else {
- $view_folder = strtr(
- rtrim($view_folder, '/\\'),
- '/\\',
- DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR
- );
- }
- } elseif (is_dir(APPPATH . $view_folder . DIRECTORY_SEPARATOR)) {
- $view_folder = APPPATH . strtr(
- trim($view_folder, '/\\'),
- '/\\',
- DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR
- );
- } else {
- header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
- echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: ' . SELF;
- exit(3); // EXIT_CONFIG
- }
- //view視圖目錄的絕對路徑
- define('VIEWPATH', $view_folder . DIRECTORY_SEPARATOR);
- //最後就是加載CI框架的核心引導文件了
- require_once BASEPATH . 'core/CodeIgniter.php';