我直的很懶,由於大概流程我已搞懂,我也懶得一步步分析了,轉載吧。
6、$config 之 import
其中 import 被傳遞給 CModule 的 setImport:
1. public function setImport($aliases)
2. {
3. foreach($aliases as $alias)
4. Yii::import($alias);
5. }
Yii::import($alias)裏的處理:
1. public static function import($alias,$forceInclude=false)
2. {
3. // 先判斷$alias是否存在於YiiBase::$_imports[] 中,已存在的直接return, 避免重複import。
4. if(isset(self::$_imports[$alias])) // previously imported
5. return self::$_imports[$alias];
6.
7. // $alias類已定義,記入$_imports[],直接返回
8. if(class_exists($alias,false))
9. return self::$_imports[$alias]=$alias;
10.
11. // 類似 urlManager 這樣的已定義於$_coreClasses[]的類,或不含.的直接類名,記入$_imports[],直接返回
12. if(isset(self::$_coreClasses[$alias]) || ($pos=strrpos($alias,'.'))===false) // a simple class name
13. {
14. self::$_imports[$alias]=$alias;
15. if($forceInclude)
16. {
17. if(isset(self::$_coreClasses[$alias])) // a core class
18. require(YII_PATH.self::$_coreClasses[$alias]);
19. else
20. require($alias.'.php');
21. }
22. return $alias;
23. }
24.
25. // 產生一個變量 $className,爲$alias最後一個.後面的部分
26. // 這樣的:'x.y.ClassNamer'
27. // $className不等於 '*', 並且ClassNamer類已定義的, ClassNamer' 記入 $_imports[],直接返回
28. if(($className=(string)substr($alias,$pos+1))!=='*' && class_exists($className,false))
29. return self::$_imports[$alias]=$className;
30.
31. // 取得 $alias 裏真實的路徑部分並且路徑有效
32. if(($path=self::getPathOfAlias($alias))!==false)
33. {
34. // $className!=='*',$className 記入 $_imports[]
35. if($className!=='*')
36. {
37. self::$_imports[$alias]=$className;
38. if($forceInclude)
39. require($path.'.php');
40. else
41. self::$_classes[$className]=$path.'.php';
42. return $className;
43. }
44. // $alias是'system.web.*'這樣的已*結尾的路徑,將路徑加到include_path中
45. else // a directory
46. {
47. set_include_path(get_include_path().PATH_SEPARATOR.$path);
48. return self::$_imports[$alias]=$path;
49. }
50. }
51. else
52. throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
53. array('{alias}'=>$alias)));
54. }
7. $config 之 components
$config 數組裏的 $components 被傳遞給CModule 的setComponents($components)
1. public function setComponents($components)
2. {
3. foreach($components as $id=>$component)
4. {
5. if($component instanceof IApplicationComponent)
6. $this->setComponent($id,$component);
7. else if(isset($this->_componentConfig[$id]))
8. $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
9. else
10. $this->_componentConfig[$id]=$component;
11. }
12. }
$componen是IApplicationComponen的實例的時候,直接賦值:
$this->setComponent($id,$component),
1. public function setComponent($id,$component)
2. {
3. $this->_components[$id]=$component;
4. if(!$component->getIsInitialized())
5. $component->init();
6. }
如果$id已存在於_componentConfig[]中(前面註冊的coreComponent),將$component 屬性加進入。
其他的component將component屬性存入_componentConfig[]中。
1. public function setImport($aliases)
2. {
3. foreach($aliases as $alias)
4. Yii::import($alias);
5. }
Yii::import($alias)裏的處理:
1. public static function import($alias,$forceInclude=false)
2. {
3. // 先判斷$alias是否存在於YiiBase::$_imports[] 中,已存在的直接return, 避免重複import。
4. if(isset(self::$_imports[$alias])) // previously imported
5. return self::$_imports[$alias];
6.
7. // $alias類已定義,記入$_imports[],直接返回
8. if(class_exists($alias,false))
9. return self::$_imports[$alias]=$alias;
10.
11. // 類似 urlManager 這樣的已定義於$_coreClasses[]的類,或不含.的直接類名,記入$_imports[],直接返回
12. if(isset(self::$_coreClasses[$alias]) || ($pos=strrpos($alias,'.'))===false) // a simple class name
13. {
14. self::$_imports[$alias]=$alias;
15. if($forceInclude)
16. {
17. if(isset(self::$_coreClasses[$alias])) // a core class
18. require(YII_PATH.self::$_coreClasses[$alias]);
19. else
20. require($alias.'.php');
21. }
22. return $alias;
23. }
24.
25. // 產生一個變量 $className,爲$alias最後一個.後面的部分
26. // 這樣的:'x.y.ClassNamer'
27. // $className不等於 '*', 並且ClassNamer類已定義的, ClassNamer' 記入 $_imports[],直接返回
28. if(($className=(string)substr($alias,$pos+1))!=='*' && class_exists($className,false))
29. return self::$_imports[$alias]=$className;
30.
31. // 取得 $alias 裏真實的路徑部分並且路徑有效
32. if(($path=self::getPathOfAlias($alias))!==false)
33. {
34. // $className!=='*',$className 記入 $_imports[]
35. if($className!=='*')
36. {
37. self::$_imports[$alias]=$className;
38. if($forceInclude)
39. require($path.'.php');
40. else
41. self::$_classes[$className]=$path.'.php';
42. return $className;
43. }
44. // $alias是'system.web.*'這樣的已*結尾的路徑,將路徑加到include_path中
45. else // a directory
46. {
47. set_include_path(get_include_path().PATH_SEPARATOR.$path);
48. return self::$_imports[$alias]=$path;
49. }
50. }
51. else
52. throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
53. array('{alias}'=>$alias)));
54. }
7. $config 之 components
$config 數組裏的 $components 被傳遞給CModule 的setComponents($components)
1. public function setComponents($components)
2. {
3. foreach($components as $id=>$component)
4. {
5. if($component instanceof IApplicationComponent)
6. $this->setComponent($id,$component);
7. else if(isset($this->_componentConfig[$id]))
8. $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
9. else
10. $this->_componentConfig[$id]=$component;
11. }
12. }
$componen是IApplicationComponen的實例的時候,直接賦值:
$this->setComponent($id,$component),
1. public function setComponent($id,$component)
2. {
3. $this->_components[$id]=$component;
4. if(!$component->getIsInitialized())
5. $component->init();
6. }
如果$id已存在於_componentConfig[]中(前面註冊的coreComponent),將$component 屬性加進入。
其他的component將component屬性存入_componentConfig[]中。
8. $config 之 params
這個很簡單
1. public function setParams($value)
2. {
3. $params=$this->getParams();
4. foreach($value as $k=>$v)
5. $params->add($k,$v);
6. }
configure 完畢!
9. attachBehaviors
$this->attachBehaviors($this->behaviors);
空的,沒動作
預創建組件對象
1. $this->preloadComponents();
2.
3. protected function preloadComponents()
4. {
5. foreach($this->preload as $id)
6. $this->getComponent($id);
7. }
getComponent() 判斷_components[] 數組裏是否有 $id的實例,如果沒有,就根據_componentConfig[$id]裏的配置來創建組件對象,調用組件的init()方法,然後存入_components[$id]中。
10. init()
this->init();
函數內:$this->getRequest();
創建了Reques 組件並初始化。
11. run()
1. public function run()
2. {
3. $this->onBeginRequest(new CEvent($this));
4. $this->processRequest();
5. $this->onEndRequest(new CEvent($this));
6. }
三 大概過程
application構造函數:
1 設置當前運行實例
2 獲取配置參數
3 設置basepath
4 設置幾個path;application,webroot ,ext
5 preinit
6 註冊error、exception處理函數 initSystemHandlers
7 加載核心組件 registerCoreComponents 包括webapplication的和application的
8 設置配置文件 configure($config)
9 附加行爲 $this->attachBehaviors($this->behaviors);
10處理加載config中的preload,//通過getComponent分別加載並初始化 $this->preloadComponents();
11 初始化init(); //加載CHttpRequest組件
run:
1 處理onBeginRequest
2 processRequest();真正處理請求
3 處理onEndRequest
webapplication->processRequest():
1 如果配置文件設置了catchAllRequest , // 'catchAllRequest'=>array('site/error','p1'=>'1','p2'=>'2'),
則所有請求都跳轉到這個controller/action這個route,並且設置$_GET參數。
2 分析url得到route,便於後面的控制器/動作創建
3 執行runController
runController:
1 創建controller, createController(),創建失敗,則拋出404錯誤
2 得到controller對象和actionID
3 控制器初始化 $controller->init();
4 最後執行 $controller->run($actionID);//真正執行頁面請求
控制器類
CController:默認控制器在CWebApplication::defaultController定義('site'),可以在配置文件修改
run():
1 //根據actionID創建action對象,這裏生成的action對象分爲定義在controller內聯動作和自定義action,比如CViewAction
$action=$this->createAction($actionID),如果創建動作失敗,missingAction拋出404錯誤
2 beforeControllerAction(beforeControllerAction定義在CWebApplication,有時也在module裏面)爲真,才執行runActionWithFilters;
3 afterControllerAction
runActionWithFilters($action,$this->filters()):
1 //如果過濾器爲空,直接運行runAction()
2 執行過濾器鏈
runAction():
1 beforeAction()返回真,才執行
2 執行$action->runWithParams();注意:這裏存在多態,每個action都可以實現這個方法, 因爲CInlineAction自己實現了runWithParams()
3 第2步驟爲真,才執行afterAction($action);
動作類 默認動作在CController::$defaultAction定義('index'),可以在CController的繼承類重新定義
runWithParams():
1 分爲2種情況,1種是內聯動作,1種是通過控制器的actions方法定義的外聯動作。
2 內聯動作 通過action+動作id作爲動作處理函數
3 外聯動作 通過調用run()函數來實現
4 如果動作方法參數個數大於0,執行runWithParamsInternal,否則直接執行動作方法。
runWithParamsInternal();
1 根據反射的方法對象得到方法的形參列表,從 控制器對象->getActionParams()得到實參,
如果實參有形參要求的參數,取其值,不然取形參默認值,否則,出錯。
2 調用動作方法 2種形式 1是action+動作id ,2是Caction的派生類(比如cviewaction)的run()
3 執行控制器的CController->render方法;$controller->render($view)
控制器類
CController:
render();
1 renderPartial();得到視圖,//先得到contact頁面的view文件內容,注意是用include的形式,所以其中的$this是指siteControlerd對象,
這裏調用了renderFile();
2 然後$output=$this->renderFile($layoutFile,array('content'=>$output),true)
把view中的內容插入到佈局頁面layouts的column1.php, 'content'和layout的頁面的$content變量相關
renderFile();
1 如果程序沒有定義viewrender,則執行controller->renderInternal();否則,執行$renderer=Yii::app()->getViewRenderer())->renderFile();
view sourceprint?發生404錯誤
errorHandler 在配置文件main中,'errorAction' => 'site/error',
**********************************************************
runActionWithFilters
過濾:
CFilterChain(繼承CList,提供數字索引存取功能,遍歷)::create($this,$action,$filters)->run();
首先創建過濾鏈,然後執行過濾
CFilterChain::create($controller,$action,$filters):
1 $chain=new CFilterChain($controller,$action);創建一個過濾鏈$chain
2 根據參數filters數組,遍歷創建過濾器$filter(字符串:通過CInlineFilter::create或者 數組:Yii::createComponent),
並且初始化$filter::init,通過$chain->add($filter)添加到過濾鏈中,並且返回這個過濾鏈$chain
注意:如果是字符串,控制器類controller必須要有"filter"+過濾器名的方法。
$chain::run();
1 如果數字索引合法,得到$filter,然後執行$filter->filter($this);
1.1 $filter->filter($this):
1 執行動作的'filter'+過濾器名稱的方法。//比如CController::filterAccessControl($filterChain);
1.1.1 CController::filterAccessControl($filterChain):
1 $filter=new CAccessControlFilter;//新建過濾器
2 $filter->setRules($this->accessRules());//設置規則
3 $filter->filter($filterChain) ;//執行過濾
4 $filter->preFilter($filterChain)爲真,繼續執行$filterChain->run();
5 $filter->postFilter($filterChain);//這個是在動作執行之後過濾
2 否則,說明過濾完畢,$this->controller->runAction($this->action); 直接執行動作。
CController:
render();
1 renderPartial();得到視圖,//先得到contact頁面的view文件內容,注意是用include的形式,所以其中的$this是指siteControlerd對象,
這裏調用了renderFile();
2 然後$output=$this->renderFile($layoutFile,array('content'=>$output),true)
把view中的內容插入到佈局頁面layouts的column1.php, 'content'和layout的頁面的$content變量相關
renderFile();
1 如果程序沒有定義viewrender,則執行controller->renderInternal();否則,執行$renderer=Yii::app()->getViewRenderer())->renderFile();
view sourceprint?發生404錯誤
errorHandler 在配置文件main中,'errorAction' => 'site/error',
**********************************************************
runActionWithFilters
過濾:
CFilterChain(繼承CList,提供數字索引存取功能,遍歷)::create($this,$action,$filters)->run();
首先創建過濾鏈,然後執行過濾
CFilterChain::create($controller,$action,$filters):
1 $chain=new CFilterChain($controller,$action);創建一個過濾鏈$chain
2 根據參數filters數組,遍歷創建過濾器$filter(字符串:通過CInlineFilter::create或者 數組:Yii::createComponent),
並且初始化$filter::init,通過$chain->add($filter)添加到過濾鏈中,並且返回這個過濾鏈$chain
注意:如果是字符串,控制器類controller必須要有"filter"+過濾器名的方法。
$chain::run();
1 如果數字索引合法,得到$filter,然後執行$filter->filter($this);
1.1 $filter->filter($this):
1 執行動作的'filter'+過濾器名稱的方法。//比如CController::filterAccessControl($filterChain);
1.1.1 CController::filterAccessControl($filterChain):
1 $filter=new CAccessControlFilter;//新建過濾器
2 $filter->setRules($this->accessRules());//設置規則
3 $filter->filter($filterChain) ;//執行過濾
4 $filter->preFilter($filterChain)爲真,繼續執行$filterChain->run();
5 $filter->postFilter($filterChain);//這個是在動作執行之後過濾
2 否則,說明過濾完畢,$this->controller->runAction($this->action); 直接執行動作。