安裝Thinkphp
怎么安裝,我就不細說了,官方文檔-安裝thinkphp說的很全了,可以通過composer、git或者直接去ThinkPHP官網下載zip包,我安裝的版本是5.0.24
測試運行
下載安裝完畢后,如果項目是下載目錄是你本地服務器的項目根目錄下,可以直接在瀏覽器輸入地址http://localhost/thinkphp5/public/,就可以進入到ThinkPHP5的默認歡迎頁,如下圖所示,這就說明ThinkPHP5已經安裝成功
立即學習“PHP免費學習筆記(深入)”;
除了上面的這個方式的地址運行,我們也可以通過apache或者nginx配置虛擬主機實現項目的訪問,有興趣的可以網上查看具體教程,然后配置虛擬主機進行訪問。
下面進入正題,我們來逐步分析ThinkPHP5的執行流程……
入口文件(publicindex.php)
打開publicindex.php文件后,我們可以看到,入口文件原始代碼如下
//?[?應用入口文件?] //?定義應用目錄 define('APP_PATH',?__DIR__?.?'/../application/'); //?加載框架引導文件 require?__DIR__?.?'/../thinkphp/start.php';
入口文件代碼很簡潔,就兩行代碼,作用分別為
define('APP_PATH',?__DIR__?.?'/../application/');定義應用目錄的常量APP_PATH require?__DIR__?.?'/../thinkphp/start.php';加載框架引導文件
除了上面的這兩個作用外,我們還可以額外在入口文件中,定義我們自己的常量,例如添加一行代碼define(‘PUBLIC_PATH’, __DIR__ .’/../public’);定義public目錄的常量以及一些預處理等
加載框架引導文件(thinkphpstart.php)
同樣的,進入thinkphpstart.php文件后,我們可以知道,代碼并不多
Namespace?think; //?ThinkPHP?引導文件 //?1.?加載基礎文件 require?__DIR__?.?'/base.php'; //?2.?執行應用 App::run()->send();
從這簡短的兩行代碼,我們可以看到,主要左右有兩個
require?__DIR__?.?'/base.php';加載基礎文件 App::run()->send();執行應用
下面兩個大點,將具體介紹這兩個左右都做了什么
加載基礎文件(thinkphpbase.php)
我們繼續打開thinkphpbase.php文件,發現這個文件終于不再像前兩個文件那樣,只有兩行代碼了……
define('THINK_VERSION',?'5.0.24'); define('THINK_START_TIME',?microtime(true)); define('THINK_START_MEM',?memory_get_usage()); define('EXT',?'.php'); define('DS',?DIRECTORY_SEPARATOR); defined('THINK_PATH')?or?define('THINK_PATH',?__DIR__?.?DS); define('LIB_PATH',?THINK_PATH?.?'library'?.?DS); define('CORE_PATH',?LIB_PATH?.?'think'?.?DS); define('TRAIT_PATH',?LIB_PATH?.?'traits'?.?DS); defined('APP_PATH')?or?define('APP_PATH',?dirname($_SERVER['SCRIPT_FILENAME'])?.?DS); defined('ROOT_PATH')?or?define('ROOT_PATH',?dirname(realpath(APP_PATH))?.?DS); defined('EXTEND_PATH')?or?define('EXTEND_PATH',?ROOT_PATH?.?'extend'?.?DS); defined('VENDOR_PATH')?or?define('VENDOR_PATH',?ROOT_PATH?.?'vendor'?.?DS); defined('RUNTIME_PATH')?or?define('RUNTIME_PATH',?ROOT_PATH?.?'runtime'?.?DS); defined('LOG_PATH')?or?define('LOG_PATH',?RUNTIME_PATH?.?'log'?.?DS); defined('CACHE_PATH')?or?define('CACHE_PATH',?RUNTIME_PATH?.?'cache'?.?DS); defined('TEMP_PATH')?or?define('TEMP_PATH',?RUNTIME_PATH?.?'temp'?.?DS); defined('CONF_PATH')?or?define('CONF_PATH',?APP_PATH);?//?配置文件目錄 defined('CONF_EXT')?or?define('CONF_EXT',?EXT);?//?配置文件后綴 defined('ENV_PREFIX')?or?define('ENV_PREFIX',?'PHP_');?//?環境變量的配置前綴 //?環境常量 define('IS_CLI',?PHP_SAPI?==?'cli'???true?:?false); define('IS_WIN',?strpos(PHP_OS,?'WIN')?!==?false); //?載入Loader類 require?CORE_PATH?.?'Loader.php'; //?加載環境變量配置文件 if?(is_file(ROOT_PATH?.?'.env'))?{ ????$env?=?parse_ini_file(ROOT_PATH?.?'.env',?true); ????foreach?($env?as?$key?=>?$val)?{ ????????$name?=?ENV_PREFIX?.?strtoupper($key); ????????if?(is_array($val))?{ ????????????foreach?($val?as?$k?=>?$v)?{ ????????????????$item?=?$name?.?'_'?.?strtoupper($k); ????????????????putenv("$item=$v"); ????????????} ????????}?else?{ ????????????putenv("$name=$val"); ????????} ????} } //?注冊自動加載 thinkLoader::register(); //?注冊錯誤和異常處理機制 thinkError::register(); //?加載慣例配置文件 thinkConfig::set(include?THINK_PATH?.?'convention'?.?EXT);
仔細一看,發現代碼雖然有六十多行,但是,代碼的作用卻顯而易見,作用主要有以下六點
- 使用define(”, ”)函數定義了很多個系統常量,外加兩個環境常量
- 引入loader類(thinkphplibrarythinkloader.php),供后續使用
- 加載環境變量配置文件(環境變量配置文件名為.env,這個文件不一定存在,都是在實際開發過程中根據需要加上去的)
- 調用thinkLoader::register()注冊自動加載機制
- 注冊系統自動加載
- Composer自動加載支持
- 注冊命名空間定義
- 加載類庫映射文件,存在于runtime緩存目錄下classmap.php
- 自動加載extend目錄
- 調用thinkError::register()注冊異常和錯誤處理機制
- 加載慣例配置文件(thinkphpconvention.php)
執行應用(thinkphplibrarythinkApp.php)下的run方法
為了方便,這個run方法的代碼雖然有點長,但是我還是選擇把整個方法貼出來,別打我哈
/** ?*?執行應用程序 ?*?@access?public ?*?@param??Request?$request?請求對象 ?*?@return?Response ?*?@throws?Exception ?*/ public?static?function?run(Request?$request?=?NULL) { ????$request?=?is_null($request)???Request::instance()?:?$request; ????try?{ ????????$config?=?self::initCommon(); ????????//?模塊/控制器綁定 ????????if?(defined('BIND_MODULE'))?{ ????????????BIND_MODULE?&&?Route::bind(BIND_MODULE); ????????}?elseif?($config['auto_bind_module'])?{ ????????????//?入口自動綁定 ????????????$name?=?pathinfo($request->baseFile(),?PATHINFO_FILENAME); ????????????if?($name?&&?'index'?!=?$name?&&?is_dir(APP_PATH?.?$name))?{ ????????????????Route::bind($name); ????????????} ????????} ????????$request->filter($config['default_filter']); ????????//?默認語言 ????????Lang::range($config['default_lang']); ????????//?開啟多語言機制?檢測當前語言 ????????$config['lang_switch_on']?&&?Lang::detect(); ????????$request->langset(Lang::range()); ????????//?加載系統語言包 ????????Lang::load([ ????????????THINK_PATH?.?'lang'?.?DS?.?$request->langset()?.?EXT, ????????????APP_PATH?.?'lang'?.?DS?.?$request->langset()?.?EXT, ????????]); ????????//?監聽?app_dispatch ????????Hook::listen('app_dispatch',?self::$dispatch); ????????//?獲取應用調度信息 ????????$dispatch?=?self::$dispatch; ????????//?未設置調度信息則進行?URL?路由檢測 ????????if?(empty($dispatch))?{ ????????????$dispatch?=?self::routeCheck($request,?$config); ????????} ????????//?記錄當前調度信息 ????????$request->dispatch($dispatch); ????????//?記錄路由和請求信息 ????????if?(self::$debug)?{ ????????????Log::record('[?ROUTE?]?'?.?var_export($dispatch,?true),?'info'); ????????????Log::record('[?HEADER?]?'?.?var_export($request->header(),?true),?'info'); ????????????Log::record('[?PARAM?]?'?.?var_export($request->param(),?true),?'info'); ????????} ????????//?監聽?app_begin ????????Hook::listen('app_begin',?$dispatch); ????????//?請求緩存檢查 ????????$request->cache( ????????????$config['request_cache'], ????????????$config['request_cache_expire'], ????????????$config['request_cache_except'] ????????); ????????$data?=?self::exec($dispatch,?$config); ????}?catch?(HttpResponseException?$exception)?{ ????????$data?=?$exception->getResponse(); ????} ????//?清空類的實例化 ????Loader::clearInstance(); ????//?輸出數據到客戶端 ????if?($data?instanceof?Response)?{ ????????$response?=?$data; ????}?elseif?(!is_null($data))?{ ????????//?默認自動識別響應輸出類型 ????????$type?=?$request->isAjax()?? ????????Config::get('default_ajax_return')?: ????????Config::get('default_return_type'); ????????$response?=?Response::create($data,?$type); ????}?else?{ ????????$response?=?Response::create(); ????} ????//?監聽?app_end ????Hook::listen('app_end',?$response); ????return?$response; }
這大概90行的代碼,具體做了什么呢,結合注釋分析,主要有以下幾步的功能
- 第一步:處理變量$request,保證有效有用不為null
- 第二步:self::initCommon()調用當前控制器中的initCommon()方法,負責初始化應用,并返回配置信息
- Loader::addNamespace(self::$namespace, APP_PATH);注冊命名空間
- self::init()調用本類的init()方法初始化應用
- 加載各種配置文件
- 加載行為擴展文件
- 加載公共文件
- 加載語言包
- 應用調試模式相關處理
- 加載額外文件,通過配置項extra_file_list的值去加載相關文件
- date_default_timezone_set($config[‘default_timezone’]);設置系統時區
- 調用Hook::listen(‘app_init’);監聽app_init標簽的行為
- 第三步:判斷是否進行模塊或者控制器的綁定
- 第四步:系統語言設置和加載
- 第五步:self::routeCheck($request, $config)加載當前控制器的routeCheck()方法進行路由檢測
- 先進行路由地址配置檢測,先讀取緩存路由,不存在再導入路由文件配置
- 無路由配置,直接解析模塊/控制器/操作
- 返回module模塊信息(模塊名、控制器名和操作方法名)
- 第六步:開啟調試模式下,記錄路由和請求信息的日志
- 第七步:self::exec($dispatch, $config)調用控制器中的exec()方法執行調用分發
- 根據用戶請求類型進行分發處理,這里是module模塊類型
- 調用self::module()執行模塊,進行模塊部署和初始化,獲取和設置當前控制器名和操作名
- 第八步:清空類的實例化,并輸出相應格式的數據到客戶端,即用戶看到的輸出界面