其实真正的核心处理是在createController,对于createController,我们着重需要了解的是下面的这段注释:
01./**
02.* ……
03.* 这个方法以下面的顺序创建一个控制器
04.* 1. 如果第一个字段在controllerMap(初始配置)中,则使用对应的控制器配置来创建控制器
05.* 2.如果第一个字段是一个模块(module)ID,则使用相应的模块来创建控制器
06.* 3.如果通过上面两项均无法创建控制器,将会搜索controllerPath(根目录对应的controller文件夹)来创建对应的控制器。
07.* ……
08.*/
09.public function createController($route,$owner=null)
10.{
11.// $owner为空则设置为$this,即 $_app对象
12.if($owner===null)
13.$owner=$this;
14.// $route为空设置为defaultController,在$config里配置
15.if(($route=trim($route,'/'))==='')
16.$route=$owner->defaultController;
17.$caseSensitive=$this->getUrlManager()->caseSensitive;
18.
19.$route.='/';
20.// 逐一取出 $route 按 ‘/’分割后的第一段进行处理
21.while(($pos=strpos($route,'/'))!==false)
22.{
23.// $id 里存放的是 $route 第一个 ‘/’前的部分
24.$id=substr($route,0,$pos);
25.if(!preg_match('/^\w+$/',$id))
26.return null;
27.if(!$caseSensitive)
28.$id=strtolower($id);
29.// $route 存放’/’后面部分
30.$route=(string)substr($route,$pos+1);
31.if(!isset($basePath))// 完整$route的第一段
32.{
33.// 如果$id在controllerMap[]里做了映射
34.// 直接根据$id创建controller对象
35.if(isset($owner->controllerMap[$id]))
36.{
37.return array(
38.Yii::createComponent($owner->controllerMap[$id],$id,$owner===$this?null:$owner),
39.$this->parseActionParams($route),
40.);
41.}
42.
43.// $id 是系统已定义的 module,根据$id取得module对象作为$owner参数来createController
44.if(($module=$owner->getModule($id))!==null)
45.return $this->createController($route,$module);
46.// 控制器所在的目录
47.$basePath=$owner->getControllerPath();
48.$controllerID='';
49.}
50.else
51.$controllerID.='/';
52.$className=ucfirst($id).'Controller';
53.$classFile=$basePath.DIRECTORY_SEPARATOR.$className.'.php';
54.// 控制器类文件存在,则require并创建控制器对象&返回
55.if(is_file($classFile))
56.{
57.if(!class_exists($className,false))
58.require($classFile);
59.if(class_exists($className,false) &&is_subclass_of($className,'CController'))
60.{
61.$id[0]=strtolower($id[0]);
62.return array(
63.new $className($controllerID.$id,$owner===$this?null:$owner),
64.$this->parseActionParams($route),
65.);
66.}
67.return null;
68.}
69.// 未找到控制器类文件,可能是多级目录,继续往子目录搜索
70.$controllerID.=$id;
71.$basePath.=DIRECTORY_SEPARATOR.$id;
72.}
73.}
也就是说,对于一个aaaa/bbbb/cccc的路由,yii首先从config/main.php中定义的controllerMap去寻找是否有名为aaaa的controller,如果有,那么就已aaaa为controller进行创建,否则再去寻找是否有名为aaaa的模块,如果有,那么就使用aaaa模块的名为bbbb的controller进行创建,否则在protected/controllers下寻找是否有名为aaaa的controller。
createController() 返回一个创建好的控制器对象和actionID, runController()调用控制器的init()方法和run($actionID)来运行控制器:
$controller->init()里没有动作,因此我们可以在自己的控制器中重写这个方法来实现初始化的时候处理数据