接上篇:Yii分析1:web程序入口(1)
然后调用了两个初始化异常/错误和注册核心组件的方法:
$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: ** 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; } }
之后这三行代码:
$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配置的类;
(未完待续)