然后调用了两个初始化异常/错误和注册核心组件的方法:
$this->initSystemHandlers();
$this->registerCoreComponents();
函数实现如下:
//初始化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的方法:
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中代码如下:
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中:
/**
* 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:
* <pre>
* 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
* ),
* )
* </pre>
*
* @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;
}
}
之后这三行代码:
$this->configure($config);
$this->attachBehaviors($this->behaviors);
$this->preloadComponents();
每一行都做了很多工作,我们一步一步分析:
$this->configure($config);
CApplication并没有configure方法,因此我们查看父类CModule的configure方法:
public function configure($config)
{
if(is_array($config))
{
foreach($config as $key=>$value)
$this->$key=$value;
}
}
是否还记得$config这个变量?其实它是一个数组包含了一些基本配置信息,例如(yii自带blog demo):
return array(
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
'name'=>'blog',
'defaultController'=>'post',
……
}
configure看起来仅仅是将数组的键值对赋值给类的变量和值,其实这里使用了__set方法,而CModule并没有__set方法,因此看他的父类CComponent:
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)));
}
接下来是:
$this->attachBehaviors($this->behaviors);
依然调用的CComponent中的方法:
public function attachBehaviors($behaviors)
{
foreach($behaviors as $name=>$behavior)
$this->attachBehavior($name,$behavior);
}
事实上,这里$this->behavior还是空的,因此这里并没有做什么事情;
之后是:
$this->preloadComponents();
调用的是CModule中的方法:
protected function preloadComponents()
{
foreach($this->preload as $id)
$this->getComponent($id);
}
是否还记得config会配置一个键名为'preload‘的数组成员?在这里会将其中的类初始化;
最后调用的方法是:
$this->init();
首先调用了CWebApplication中的init方法:
protected function init()
{
parent::init();
// preload 'request' so that it has chance to respond to onBeginRequest event.
$this->getRequest();
}
其中调用了父类的父类CModule中的方法init:
protected function init()
{
}
没有做任何事
到这里,new CreateWebApplication的工作全部完成,主要过程总结如下:
读取配置文件;
将配置文件中的数组成员赋值给成员变量;
初始化preload配置的类;
(未完待续)