接上篇:Yii分析1:web程序入口(1)
然后调用了两个初始化异常/错误和注册核心组件的方法:
1
2
|
$this->initSystemHandlers();
$this->registerCoreComponents();
|
函数实现如下:
1
2
3
4
5
6
7
8
|
//初始化errorhandler和exceptionhandler
protected function initSystemHandlers()
{
if(YII_ENABLE_EXCEPTION_HANDLER)
set_exception_handler(array($this,'handleException'));
if(YII_ENABLE_ERROR_HANDLER)
set_error_handler(array($this,'handleError'),error_reporting());
}
|
registerCoreComponents调用了CWebApplication的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
protected function registerCoreComponents()
{
parent::registerCoreComponents();
$compOnents=array(
//url路由类
'urlManager'=>array(
'class'=>'CUrlManager',
),
//http请求处理类
'request'=>array(
'class'=>'CHttpRequest',
),
//session
处理类
'session'=>array(
'class'=>'CHttpSession',
),
//assets文件管理类
'assetManager'=>array(
'class'=>'CAssetManager',
),
//用户类
'user'=>array(
'class'=>'CWebUser',
),
//主题管理类
'themeManager'=>array(
'class'=>'CThemeManager',
),
//认证管理类
'authManager'=>array(
'class'=>'CPhpAuthManager',
),
//客户端脚本管理类
'clientScript'=>array(
'class'=>'CClientScript',
),
);
$this->setComponents($components);
}
|
其中CWebApplication的parent中代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
protected function registerCoreComponents()
{
$compOnents=array(
//消息类(国际化)
'coreMessages'=>array(
'class'=>'CPhpMessageSource',
'language'=>'en_us',
'basePath'=>YII_PATH.DIRECTORY_SEPARATOR.'messages',
),
//数据库类
'db'=>array(
'class'=>'CDbConnection',
),
'messages'=>array(
'class'=>'CPhpMessageSource',
),
//错误处理
'errorHandler'=>array(
'class'=>'CErrorHandler',
),
//安全处理类
'securityManager'=>array(
'class'=>'CSecurityManager',
),
//基于文件的持久化存储类
'statePersister'=>array(
'class'=>'CStatePersister',
),
);
$this->setComponents($components);
}
|
setComponents定义在CModule中:
* array( * 'db'=>array( * 'class'=>'CDbConnection', * 'connectionString'=>'sqlite:path/to/file.db', * ), * 'cache'=>array( * 'class'=>'CDbCache', * 'connectionID'=>'db', * 'enabled'=>!YII_DEBUG, // enable caching in non-debug mode * ), * ) ** * @param array application components(id=>component configuration or instances) */ public function setComponents($components) { foreach($components as $id=>$component) { //如果继承了IApplicationComponent,则立即set,否则放进_componentConfig数组中 if($component instanceof IApplicationComponent) $this->setComponent($id,$component); else if(isset($this->_componentConfig[$id])) $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component); else $this->_componentConfig[$id]=$component; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
/**
* Sets the application components.
*
* When a configuration is used to specify a component, it should consist of
* the component's initial property values (name-value pairs). Additionally,
* a component can be enabled (default) or disabled by specifying the 'enabled' value
* in the configuration.
*
* If a configuration is specified with an ID that is the same as an existing
* component or configuration, the existing one will be replaced silently.
*
* The following is the configuration for two components:
*
* array(
* 'db'=>array(
* 'class'=>'CDbConnection',
* 'connectionString'=>'sqlite:path/to/file.db',
* ),
* 'cache'=>array(
* 'class'=>'CDbCache',
* 'connectionID'=>'db',
* 'enabled'=>!YII_DEBUG, // enable caching in non-debug mode
* ),
* )
*
*
* @param array application components(id=>component configuration or instances)
*/
public function setComponents($components)
{
foreach($components as $id=>$component)
{
//如果继承了IApplicationComponent,则立即set,否则放进_componentConfig数组中
if($component instanceof IApplicationComponent)
$this->setComponent($id,$component);
else if(isset($this->_componentConfig[$id]))
$this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
else
$this->_componentConfig[$id]=$component;
}
}
|
之后这三行代码:
1
2
3
|
$this->configure($config);
$this->attachBehaviors($this->behaviors);
$this->preloadComponents();
|
每一行都做了很多工作,我们一步一步分析:
1
|
$this->configure($config);
|
CApplication并没有configure方法,因此我们查看父类CModule的configure方法:
1
2
3
4
5
6
7
8
|
public function configure($config)
{
if(is_array($config))
{
foreach($config as $key=>$value)
$this->$key=$value;
}
}
|
是否还记得$config这个变量?其实它是一个数组包含了一些基本配置信息,例如(yii自带blog demo):
1
2
3
4
5
6
|
return array(
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
'name'=>'blog',
'defaultController'=>'post',
……
}
|
configure看起来仅仅是将数组的键值对赋值给类的变量和值,其实这里使用了__set方法,而CModule并没有__set方法,因此看他的父类CComponent:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public function __set($name,$value)
{
$setter='set'.$name;
//如果set开头的方法存在,则调用set方法进行赋值
if(method_exists($this,$setter))
$this->$setter($value);
//如果有on开通的事件函数,则调用该事件函数处理
else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
{
// duplicating getEventHandlers() here for performance
$name=strtolower($name);
if(!isset($this->_e[$name]))
$this->_e[$name]=new CList;
$this->_e[$name]->add($value);
}
//如果只存在get方法,那么说明这个属性是制度的,抛出异常
else if(method_exists($this,'get'.$name))
throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
array('{class}'=>get_class($this), '{property}'=>$name)));
//否则抛出异常
else
throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
array('{class}'=>get_class($this), '{property}'=>$name)));
}
|
接下来是:
1
|
$this->attachBehaviors($this->behaviors);
|
依然调用的CComponent中的方法:
1
2
3
4
5
|
public function attachBehaviors($behaviors)
{
foreach($behaviors as $name=>$behavior)
$this->attachBehavior($name,$behavior);
}
|
事实上,这里$this->behavior还是空的,因此这里并没有做什么事情;
之后是:
1
|
$this->preloadComponents();
|
调用的是CModule中的方法:
1
2
3
4
5
|
protected function preloadComponents()
{
foreach($this->preload as $id)
$this->getComponent($id);
}
|
是否还记得config会配置一个键名为’preload‘的数组成员?在这里会将其中的类初始化;
最后调用的方法是:
1
|
$this->init();
|
首先调用了CWebApplication中的init方法:
1
2
3
4
5
6
|
protected function init()
{
parent::init();
// preload 'request' so that it has chance to respond to onBeginRequest event.
$this->getRequest();
}
|
其中调用了父类的父类CModule中的方法init:
1
2
3
|
protected function init()
{
}
|
没有做任何事
到这里,new CreateWebApplication的工作全部完成,主要过程总结如下:
读取配置文件;
将配置文件中的数组成员赋值给成员变量;
初始化preload配置的类;