我直的很懒,由于大概流程我已搞懂,我也懒得一步步分析了,转载吧。
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); 直接执行动作。