Thinkphp app類分析

// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <[email protected]>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP 應用程序類 執行應用過程管理
*/
class App{
 
/**
* 應用程序初始化
* @access public
* @return void
*/
staticpublic functioninit(){
// 加載動態應用公共文件和配置
/*
此函數定義在公共函數庫中,主要是用來加載指定路徑目錄下的各種文件,主要是自定義的函數文件和自定義的配置文件
*/
load_ext_file(COMMON_PATH);
 
// 定義當前請求的系統常量
/*
此處定義了請求開始時候的時間。
下面說一下time函數和$_SERVER['REQUEST_TIME']的區別:
比如一個php應用,time獲取的時候是time執行時那個時刻的時間。但是後者$_SERVER['REQUEST_TIME']不管在哪裏獲得的時間都是php應用執行第一行那個時刻的時間。
*/
define('NOW_TIME',$_SERVER['REQUEST_TIME']);
/*
獲得請求的方法。這裏支持四中:get,post,put和delete
關於http協議中請求方法的區別:請看http://www.flypeng.com/1574/news.html
*/
define('REQUEST_METHOD',$_SERVER['REQUEST_METHOD']);
define('IS_GET',REQUEST_METHOD =='GET'? true: false);
define('IS_POST',REQUEST_METHOD =='POST'? true: false);
define('IS_PUT',REQUEST_METHOD =='PUT'? true: false);
define('IS_DELETE',REQUEST_METHOD =='DELETE'? true: false);
/*
可以學習到怎樣判斷是ajax請求。
tp提供兩種判斷方法,第一種是判斷http協議中的變量,第二種是自定義變量
參考:http://my.oschina.net/junn/blog/150273
*/
define('IS_AJAX',((isset($_SERVER['HTTP_X_REQUESTED_WITH'])&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])== 'xmlhttprequest')|| !empty($_POST[C('VAR_AJAX_SUBMIT')])|| !empty($_GET[C('VAR_AJAX_SUBMIT')]))? true: false);
 
// URL調度
/*
此類爲mvc框架的核心類。主要用於從url中解析出模塊,控制器和操作以及參數。爲後面的程序執行提供必需的基礎。
之後開闢章節來講述。
*/
Dispatcher::dispatch();
 
// URL調度結束標籤
/*
在這裏tp使用了鉤子功能。可以讓開發者在url調度後添加自己的自定義代碼。
Hook類以後開闢章節來講述。
*/
Hook::listen('url_dispatch');
 
// 日誌目錄轉換爲絕對路徑
C('LOG_PATH',realpath(LOG_PATH).'/'.MODULE_NAME.'/');
// TMPL_EXCEPTION_FILE 改爲絕對地址
C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE')));
return;
}
 
/**
* 執行應用程序
* @access public
* @return void
*/
staticpublic functionexec(){
/*
控制器名稱的安全監測。
經過url調度類解析後會從url中解析出控制器名稱。那麼這裏就是要對解析出來的控制器名稱做安全監測。
^[A-Za-z](\/|\w)*$可以匹配形如asas/asa     asas     asas/  這樣的形式
如果匹配不到,就把$module設置爲false
*/
if(!preg_match('/^[A-Za-z](\/|\w)*$/',CONTROLLER_NAME)){// 安全檢測
$module= false;
}elseif(C('ACTION_BIND_CLASS')){
//下面是tp的功能“操作綁定到類”的實現代碼。
/*
主要思路:
一般http://serverName/Home/Index/index這種url解析出來的模塊名是Home。控制器名是Index,操作名稱index。
組合出的路徑應該是Application/Home/Controller/<span class="typ">IndexController</span><span class="pun">.</span><span class="kwd">class</span><span class="pun">.</span><span class="pln">php裏面定義的index方法。
</span>但是我們一旦定義了操作綁定到類,類似上述的url解析出來的模塊名是Home。控制器名是Index,操作名稱index。
但是組合的路徑有差別:Application/Home/Controller/Index/index.class.php中的run方法。
注意差別,如果我們定義了操作綁定到類,那麼我們就得在指定的控制器文件夾下創建一個同操作名稱相同的類。在類裏面定義run方法用於執行。
*/
// 操作綁定到類:模塊\Controller\控制器\操作
$layer= C('DEFAULT_C_LAYER');
if(is_dir(MODULE_PATH.$layer.'/'.CONTROLLER_NAME)){
$namespace= MODULE_NAME.'\\'.$layer.'\\'.CONTROLLER_NAME.'\\';
}else{
// 空控制器
//如果找不到url解析出來的控制器,那麼就調用空控制器。也就是Controller目錄下的_empty目錄下的執行操作
$namespace= MODULE_NAME.'\\'.$layer.'\\_empty\\';
}
//操作名稱
$actionName =strtolower(ACTION_NAME);
//組合出實際調用了類路徑。如果沒有找到,那麼定義空操作。那麼就會執行空操作裏面的run方法
if(class_exists($namespace.$actionName)){
$class= $namespace.$actionName;
}elseif(class_exists($namespace.'_empty')){
// 空操作
$class =$namespace.'_empty';
}else{
E(L('_ERROR_ACTION_').':'.ACTION_NAME);
}
$module =new $class;
// 操作綁定到類後 固定執行run入口
$action ='run';
}else{
//創建控制器實例
$module= controller(CONTROLLER_NAME,CONTROLLER_PATH);
}
/*
到此爲止,我們應該可以得到一個實例化的類了。
如果是操作綁定到類的話,那麼$mouble類應該是  控制器/類。action=run
如果不是,那麼$moudle類他應該是控制器類。action=url解析出的參數方法
*/
if(!$module){
if('4e5e5d7364f443e28fbf0d3ae744a59a'== CONTROLLER_NAME){
header("Content-type:image/png");
exit(base64_decode(App::logo()));
}
 
// 是否定義Empty控制器
$module= A('Empty');
if(!$module){
E(L('_CONTROLLER_NOT_EXIST_').':'.CONTROLLER_NAME);
}
}
 
// 獲取當前操作名 支持動態路由
if(!isset($action)){
$action= ACTION_NAME.C('ACTION_SUFFIX');
}
try{
if(!preg_match('/^[A-Za-z](\w)*$/',$action)){
// 非法操作
throw new\ReflectionException();
}
//執行當前操作
/*
利用反射得到控制器類的方法信息
*/
$method =new \ReflectionMethod($module,$action);
/*
只有此方法是public或者static才允許執行
*/
if($method->isPublic()&& !$method->isStatic()){
/*
這裏爲什麼要用反射?不用直接拼湊字符串然後實例化呢?
個人理解:爲了後面使用反射的高級方法判斷前置和後置操作
*/
$class= new\ReflectionClass($module);
// 前置操作
if($class->hasMethod('_before_'.$action)){
$before =$class->getMethod('_before_'.$action);
if($before->isPublic()){
$before->invoke($module);
}
}
// URL參數綁定檢測
/*
如果方法的參數大於0,並且設置了參數綁定(什麼是參數綁定,參照官方文檔)
如果當真設置了參數綁定,那麼經過url解析後會把url中的參數解析到$_GET變量中。
所以這裏僅僅需要把post和put提交的參數合併到get即可。
關於反射:http://blog.csdn.net/salc3k/article/details/7287387
*/
if($method->getNumberOfParameters()>0&& C('URL_PARAMS_BIND')){
switch($_SERVER['REQUEST_METHOD']){
case 'POST':
$vars= array_merge($_GET,$_POST);
break;
case'PUT':
parse_str(file_get_contents('php://input'),$vars);
break;
default:
$vars= $_GET;
}
//得到方法中的參數
$params =$method->getParameters();
//得到定義的參數綁定類型。如果是1的話表示按順序綁定
$paramsBindType =C('URL_PARAMS_BIND_TYPE');
foreach($paramsas $param){
$name =$param->getName();
if(1 ==$paramsBindType && !empty($vars)){
$args[]= array_shift($vars);
}elseif(0 ==$paramsBindType && isset($vars[$name])){
$args[]= $vars[$name];
}elseif($param->isDefaultValueAvailable()){
$args[]= $param->getDefaultValue();
}else{
E(L('_PARAM_ERROR_').':'.$name);
}
}
// 開啓綁定參數過濾機制
/
*
這裏使用了array_walk_recursive函數。
首先tp默認會對傳進來的args參數調用函數filter_exp進行過濾檢測。
其次,還允許開發者定義自己的過濾函數,tp會依次調用。
這裏還用到了tp自己內置的一個函數array_map_recursive。裏面主要是遞歸對參數進行過濾。
以後分析。
*
/
if(C('URL_PARAMS_SAFE')){
array_walk_recursive($args,'filter_exp');
$filters= C('URL_PARAMS_FILTER')?:C('DEFAULT_FILTER');
if($filters){
$filters= explode(',',$filters);
foreach($filtersas $filter){
$args= array_map_recursive($filter,$args);// 參數過濾
}
}
}
$method->invokeArgs($module,$args);
}else{
$method->invoke($module);
}
// 後置操作
if($class->hasMethod('_after_'.$action)){
$after= $class->getMethod('_after_'.$action);
if($after->isPublic()){
$after->invoke($module);
}
}
}else{
// 操作方法不是Public 拋出異常
throw new\ReflectionException();
}
} catch(\ReflectionException$e){
// 方法調用發生異常後 引導到__call方法處理
$method =new \ReflectionMethod($module,'__call');
$method->invokeArgs($module,array($action,''));
}
return;
}
 
/**
* 運行應用實例 入口文件使用的快捷方法
* @access public
* @return void
*/
staticpublic functionrun(){
// 應用初始化標籤
/*
此鉤子允許應用開發者在應用加載之前做一些事情
*/
Hook::listen('app_init');
//開始加載應用
App::init();
// 應用開始標籤
Hook::listen('app_begin');
// Session初始化
if(!IS_CLI){
session(C('SESSION_OPTIONS'));
}
// 記錄應用初始化時間
G('initTime');
//執行,具體解釋看對應的方法
App::exec();
// 應用結束標籤
Hook::listen('app_end');
return;
}
 
static publicfunction logo(){
return'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/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';
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章