`
miaojihao
  • 浏览: 22671 次
  • 性别: Icon_minigender_1
  • 来自: 南阳
社区版块
存档分类
最新评论

yii源代码之旅(4)

 
阅读更多

 调用 registerCoreComponents 函数

 

/**
	 * Registers the core application components.
	 * @see setComponents
	 */
	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',
			),
			'urlManager'=>array(
				'class'=>'CUrlManager',
			),
			'request'=>array(
				'class'=>'CHttpRequest',
			),
			'format'=>array(
				'class'=>'CFormatter',
			),
		);

		$this->setComponents($components);
	}

 首先一个数组,调用setComponents,将该数组传递进去。

setComponents如下:

public function setComponents($components,$merge=true)
	{
		
		foreach($components as $id=>$component){
			
			$this->setComponent($id,$component,$merge);
		}
	public function setComponent($id,$component,$merge=true)
	{

		if($component===null)
		{
			unset($this->_components[$id]);
			return;
		}
		elseif($component instanceof IApplicationComponent)
		{
			$this->_components[$id]=$component;

			if(!$component->getIsInitialized())
				$component->init();

			return;
		}
		elseif(isset($this->_components[$id]))
		{
			if(isset($component['class']) && get_class($this->_components[$id])!==$component['class'])
			{
				unset($this->_components[$id]);
				$this->_componentConfig[$id]=$component; //we should ignore merge here
				return;
			}

			foreach($component as $key=>$value)
			{
				if($key!=='class')
					$this->_components[$id]->$key=$value;
			}
		}
		elseif(isset($this->_componentConfig[$id]['class'],$component['class'])
			&& $this->_componentConfig[$id]['class']!==$component['class'])
		{
			
			$this->_componentConfig[$id]=$component; //we should ignore merge here
			return;
		}
		
		if(isset($this->_componentConfig[$id]) && $merge){
			$this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
		}
		else{
			$this->_componentConfig[$id]=$component;
		}
		
		
	}
 
如果$component 为null,注销掉$this->_components里面对应的key
如果$component实现了IApplicationComponent接口,很显然,该$component是数组
如果$this->_components的对应的key存在,即$this->_components[$id]存在,呢么
判断$component['class'] 存在,并且 通过get_class 获取 $this->_components[$id] 的类名,判断是否和$component['class']相等。如果都为true,注销掉$this->_components[$id],将$this->_componentConfig[$id]=$component,返回,
判断$component['class']不存在,或者$this->_components[$id]的类名和$component['class']不等,呢么
foreach 循环$component, key value
循环体里面,如果key不等于字符串'class',$this->_components[$id]->$key=$value;
如果$this->_componentConfig[$id]存在,$merge为true
类CMap调用其静态方法mergeArray,方法如下:
	public static function mergeArray($a,$b)
	{
		$args=func_get_args();
		$res=array_shift($args);
		while(!empty($args))
		{
			$next=array_shift($args);
			foreach($next as $k => $v)
			{
				if(is_integer($k))
					isset($res[$k]) ? $res[]=$v : $res[$k]=$v;
				elseif(is_array($v) && isset($res[$k]) && is_array($res[$k]))
					$res[$k]=self::mergeArray($res[$k],$v);
				else
					$res[$k]=$v;
			}
		}
		return $res;
	}



 将合并后的对象赋值给$this->_componentConfig[$id]
最后$this->_componentConfig[$id]=$component;
返回到构造函数。
 调用配置方法configure(),将配置数组传递进去。
public function configure($config)
	{
		if(is_array($config))
		{
			foreach($config as $key=>$value){
				$this->$key=$value;
				
			}
		}
	}
 该方法很简单,就是判断是数组,循环该数组,
循环体中将$value的值赋值个$this->$key.
$config的数组体是:
array(
 'name'=>'Yii Blog Demo',
 // preloading 'log' component
 'preload'=>array('log'),
 // autoloading model and component classes
 'import'=>array(
  'application.models.*',
  'application.components.*',
 ),
 'defaultController'=>'post',
‘components’=>array(
 
),
'params'=>'.../'
);
$this 指的是CWebApplication,因为其父类的父类的父类有魔术方法__set,__get,所以在给其属性设置值得时候,会自动调用CComponent的__set方法,
public function __set($name,$value)
	{
		
		$setter='set'.$name;
		if(method_exists($this,$setter))
			return $this->$setter($value);
		elseif(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;
			return $this->_e[$name]->add($value);
		}
		elseif(is_array($this->_m))
		{
			foreach($this->_m as $object)
			{
				if($object->getEnabled() && (property_exists($object,$name) || $object->canSetProperty($name)))
					return $object->$name=$value;
			}
		}
		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)));
	}
 2个参数,第一个是属性,第二个是值。
参数分别是:‘name’,‘preload’,‘import’,‘defaultController’,‘components’,‘params’
$setter = 'setname' ,‘setpreload’,'setimport','setdefaultController','setcomponents','setparams'
判断这些方法如果存在,调用这些方法,由于属性name,preload,defaultController存在,故直接赋值,而import,components,params不存在,调用setImport,setComponents,setparams方法:
public function setImport($aliases)
	{
		foreach($aliases as $alias)
			Yii::import($alias);
	}
 循环$aliases,即配置里面配置的内容。
调用Yii的import方法,将值传入。方法如下:
	public static function import($alias,$forceInclude=false)
	{
		if(isset(self::$_imports[$alias]))  // previously imported
			return self::$_imports[$alias];

		if(class_exists($alias,false) || interface_exists($alias,false))
			return self::$_imports[$alias]=$alias;

		if(($pos=strrpos($alias,'\\'))!==false) // a class name in PHP 5.3 namespace format
		{
			$namespace=str_replace('\\','.',ltrim(substr($alias,0,$pos),'\\'));
			if(($path=self::getPathOfAlias($namespace))!==false)
			{
				$classFile=$path.DIRECTORY_SEPARATOR.substr($alias,$pos+1).'.php';
				if($forceInclude)
				{
					if(is_file($classFile))
						require($classFile);
					else
						throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing PHP file and the file is readable.',array('{alias}'=>$alias)));
					self::$_imports[$alias]=$alias;
				}
				else
					self::$classMap[$alias]=$classFile;
				return $alias;
			}
			else
				throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory.',
					array('{alias}'=>$namespace)));
		}

		if(($pos=strrpos($alias,'.'))===false)  // a simple class name
		{
			if($forceInclude && self::autoload($alias))
				self::$_imports[$alias]=$alias;
			return $alias;
		}

		$className=(string)substr($alias,$pos+1);
		$isClass=$className!=='*';

		if($isClass && (class_exists($className,false) || interface_exists($className,false)))
			return self::$_imports[$alias]=$className;

		if(($path=self::getPathOfAlias($alias))!==false)
		{
			if($isClass)
			{
				if($forceInclude)
				{
					if(is_file($path.'.php'))
						require($path.'.php');
					else
						throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing PHP file and the file is readable.',array('{alias}'=>$alias)));
					self::$_imports[$alias]=$className;
				}
				else
					self::$classMap[$className]=$path.'.php';
				return $className;
			}
			else  // a directory
			{
				if(self::$_includePaths===null)
				{
					self::$_includePaths=array_unique(explode(PATH_SEPARATOR,get_include_path()));
					if(($pos=array_search('.',self::$_includePaths,true))!==false)
						unset(self::$_includePaths[$pos]);
				}

				array_unshift(self::$_includePaths,$path);

				if(self::$enableIncludePath && set_include_path('.'.PATH_SEPARATOR.implode(PATH_SEPARATOR,self::$_includePaths))===false)
					self::$enableIncludePath=false;

				return self::$_imports[$alias]=$path;
			}
		}
		else
			throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
				array('{alias}'=>$alias)));
	}
 按下不表。
setparams方法:
/**
	 * Sets user-defined parameters.
	 * @param array $value user-defined parameters. This should be in name-value pairs.
	 */
	public function setParams($value)
	{
		$params=$this->getParams();
		foreach($value as $k=>$v)
			$params->add($k,$v);
	}
 先调用getParams方法,获取该方法返回信息
/**
	 * Returns user-defined parameters.
	 * @return CAttributeCollection the list of user-defined parameters
	 */
	public function getParams()
	{
		if($this->_params!==null)
			return $this->_params;
		else
		{
			$this->_params=new CAttributeCollection;
			$this->_params->caseSensitive=true;
			return $this->_params;
		}
	}
 显然$this->_params为null,故
新实例化一个CAttributeCollection对象。由于该类继承CMap,并且CMap继承CComponent,且实现IteratorAggregate,ArrayAccess,Countable3个接口。
CMap类包含2个私有属性,private $_d = array();private $_r = false;
$_r是否只读。
由于CAttributeCollection类没有构造函数,所以调用其父类CMap的构造函数。
CMap的构造函数如下:
public function __construct($data=null,$readOnly=false)
	{
		if($data!==null)
			$this->copyFrom($data);
		$this->setReadOnly($readOnly);
	}
 默认参数。$data是null,调用$this->setReadOnly,设置$_r为false
调用对象的caseSensitive = true
将该对象返回。
回到setParams方法里面。
循环$value,这里的$value是配置参数里面对应的,
 
array(
	// this is displayed in the header section
	'title'=>'My Yii Blog',
	// this is used in error pages
	'adminEmail'=>'webmaster@example.com',
	// number of posts displayed per page
	'postsPerPage'=>10,
	// maximum number of comments that can be displayed in recent comments portlet
	'recentCommentCount'=>10,
	// maximum number of tags that can be displayed in tag cloud portlet
	'tagCloudCount'=>20,
	// whether post comments need to be approved before published
	'commentNeedApproval'=>true,
	// the copyright information displayed in the footer section
	'copyrightInfo'=>'Copyright © 2009 by My Company.',
)
 
循环调用刚获取的CAttributeCollects对象的add方法, 参数分别是key,value
add方法如下:
public function add($key,$value)
	{
		if($this->caseSensitive)
			parent::add($key,$value);
		else
			parent::add(strtolower($key),$value);
	}
 由于改对象caseSensitive为true,调用其父类的方法add,
方法如下:
public function add($key,$value)
	{
		if(!$this->_r)
		{
			if($key===null)
				$this->_d[]=$value;
			else
				$this->_d[$key]=$value;
		}
		else
			throw new CException(Yii::t('yii','The map is read only.'));
	}
 将key,value,放入$_d中。
返回到构造函数。
调用attachBehaviors方法,空的。
调用preloadComponents方法。如下:
/**
	 * Loads static application components.
	 */
	protected function preloadComponents()
	{
		foreach($this->preload as $id)
			$this->getComponent($id);
	}
 循环$this->preload,这个值来源于配置参数,在构造函数调用$this->configre($confige)赋值的。
array('log');
在循环体里面调用getComponent,将‘log’传递进去。
方法如下:
public function getComponent($id,$createIfNull=true)
	{
		if(isset($this->_components[$id]))
			return $this->_components[$id];
		elseif(isset($this->_componentConfig[$id]) && $createIfNull)
		{
			$config=$this->_componentConfig[$id];
			if(!isset($config['enabled']) || $config['enabled'])
			{
				Yii::trace("Loading \"$id\" application component",'system.CModule');
				unset($config['enabled']);
				$component=Yii::createComponent($config);
				$component->init();
				return $this->_components[$id]=$component;
			}
		}
	}

知道$this->_components为空。

而且$this->_componentConfig里面的log对应的数组有2个元素。

$config = array(

Class =>CLogRouter

Routes =>array(

Class =>CFileLogRoute

Levels =>error,warning

)

 

)

调用Yii::tracexxxxxxx;

<!--EndFragment--> 调用YiicreateComponent方法,将$configure传入。<!--EndFragment-->
 
public static function createComponent($config)
	{
		if(is_string($config))
		{
			$type=$config;
			$config=array();
		}
		elseif(isset($config['class']))
		{
			$type=$config['class'];
			unset($config['class']);
		}
		else
			throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.'));

		if(!class_exists($type,false))
			$type=Yii::import($type,true);

		if(($n=func_num_args())>1)
		{
			$args=func_get_args();
			if($n===2)
				$object=new $type($args[1]);
			elseif($n===3)
				$object=new $type($args[1],$args[2]);
			elseif($n===4)
				$object=new $type($args[1],$args[2],$args[3]);
			else
			{
				unset($args[0]);
				$class=new ReflectionClass($type);
				// Note: ReflectionClass::newInstanceArgs() is available for PHP 5.1.3+
				// $object=$class->newInstanceArgs($args);
				$object=call_user_func_array(array($class,'newInstance'),$args);
			}
		}
		else
			$object=new $type;

		foreach($config as $key=>$value)
			$object->$key=$value;

		return $object;
	}
 

参数的结构是$config = array(

Class =>CLogRouter

Routes =>array(

Class =>CFileLogRoute

Levels =>error,warning

)

 

)

满足条件,将$config[Class]赋值给$type,$type=CLogRouter

注销掉key class,

调用class_exists判断$type类是否存在,第二个参数是false,不自动导入。如果不存在,调用Yii import方法导入

调用func_num_args,获取参数个数。参数等于1,实例化一个$type

 

Foreach循环 $config key=>val

 

此时

$config = array(

Routes =>array(

Class =>CFileLogRoute

Levels =>error,warning

)

)

循环体内部调用$type(CLogRouter)的属性,

由于没有该属性,自动调用其父类的魔术方法__set。如下

<!--EndFragment-->

判断setroutes方法存在

Foreach 循环 配置参数

$this->_routes 键值填充。

<!--EndFragment-->

 

将返回的对象赋值给$componentCLogRouter 继承CApplicationComponent 

调用其init()方法

 

public function init()
	{
		parent::init();
		foreach($this->_routes as $name=>$route)
		{
			$route=Yii::createComponent($route);
			$route->init();
			$this->_routes[$name]=$route;
		}
		Yii::getLogger()->attachEventHandler('onFlush',array($this,'collectLogs'));
		Yii::app()->attachEventHandler('onEndRequest',array($this,'processLogs'));
	}

 

按下不表。
返回构造函数
调用初始化方法init()
protected function init()
	{
		parent::init();
		// preload 'request' so that it has chance to respond to onBeginRequest event.
		$this->getRequest();
	}
 调用父类的初始化方法空的。
调用getRequest()方法,获取组件
public function getRequest()
	{
		return $this->getComponent('request');
	}
 调用getComponent方法,将request字符串传递进去。
//至此,初始化完毕。
 
 
分享到:
评论

相关推荐

    yii项目源代码

    本项目源代码是基于Yii框架构建的一个实际应用,对于初学者而言,这是一个很好的学习资源,能够帮助他们深入理解Yii的工作原理和最佳实践。 首先,让我们详细了解一下Yii框架的核心特性。Yii提供了一种模型-视图-...

    yii框架源代码

    标题“yii框架源代码”意味着我们将深入探讨Yii框架的核心结构和实现细节。源代码是理解任何软件系统工作原理的关键,对于开发者来说,查看源代码有助于学习框架设计模式,提高编程技能,以及对框架进行定制和扩展。...

    用Yii写的商城源代码

    这个“用Yii写的商城源代码”很可能是孙海华老师在传智播客的一门课程中的实践项目,旨在帮助学员理解如何利用Yii框架构建一个完整的电子商务平台。在这个项目中,我们可以深入学习到以下几个关键的Yii和商城开发的...

    《Yii框架深度剖析》配套代码

    本书不是简单地介绍如何使用 Yii 框架,而是站在框架设计的高度,从源代码级别深 度剖析。本书首先介绍 PHP 框架技术的概念及其应用领域,然后开始仿照 Yii 框架源代码 自定义框架,其中包括了 MVC 设计模式、单入口...

    YII2框架代码

    4. 数据库操作:YII2的ActiveRecord模式简化了数据库操作,提供了强大的查询构建器,支持ORM(对象关系映射),可以方便地进行CRUD操作。 5. 安全性:YII2内置了各种安全防护措施,如输入验证、CSRF(跨站请求伪造...

    yii框架代码

    yii 框架 文件,方便搭建环境,分析代码等等

    yii2医疗实例

    “master”可能是这个项目的主分支名称,暗示着源代码管理和版本控制的重要性。开发者可以通过Git等工具对代码进行版本控制,协同开发,保证团队工作的高效性。 总之,“yii2医疗实例”不仅展示了Yii2框架的强大...

    Yii2-Admin 后台模板源代码文件

    系统基于yii2高级版本开发,后台模板使用的 Ace Admin。对于一般的后台开发,比较方便; 对于数据表的CURL操作都有封装,且所有操作都有权限控制。现在这个项目只是一个示例项目, 主要功能被我移到: [jinxing/yii2-...

    深入理解Yii2.0

    采用的方式是分析框架的源代码,尝试从根上进行理解和阐述,并融入个人使用Yii开发的一些经验和教训。 通过本书,你将不仅仅了解到Yii怎么使用的实操技巧,还将掌握其实现的技术原理和内幕。 更为重要的是,接触...

    禅道7.0源代码

    "禅道7.0源代码"是一个开源项目管理软件的核心代码库,专为中国的软件开发团队设计,旨在提供全面的项目管理解决方案。该版本的源代码代表了禅道在7.0阶段的功能实现和系统架构,是理解禅道运作机制、进行二次开发或...

    yii框架中文手册教程和YII模板

    解压后,开发者可以查看源代码,了解框架内部的工作机制,也可以根据需求进行自定义修改。此外,版本号中的“r3324”表示这是框架的第3324次提交,反映了框架的持续改进和更新。 “yii框架中文手册教程.pdf”是Yii...

    yii2 通用后台系统

    在文件名称列表 "ytwo" 中,可能包含了该后台系统的源代码文件,例如配置文件、模型类、控制器、视图文件、公共函数库等。开发者可以通过查看这些文件深入了解系统架构和实现细节,以便进行二次开发或定制。 总的来...

    yii框架中文文档、yii中文手册教程

    Yii框架以性能优化为设计核心,提供了一系列现代化的Web开发工具和技术,使得开发者可以快速、高效地编写高质量的代码。 在“yii1.1中文文档”中,包含了Yii 1.1版本的详尽教程和参考指南。这个版本是Yii框架的一个...

    yii2swoole让yii2运行在swoole上

    6. **协程(Coroutine)**:Swoole的协程机制能让开发者以同步代码的方式编写异步程序,降低了异步编程的复杂性,同时也提高了代码的可读性和可维护性。 7. **事件驱动**:Swoole提供了丰富的事件机制,如连接建立、...

    Yii框架学习笔记.pdf

    附录部分通常包含了对文档中未详细说明的内容的补充,例如对源代码的额外说明、配置项的解释、或者对某些操作的高级技巧等。 以上便是Yii框架学习笔记的核心内容,涵盖了从基础入门到高级特性的全面知识点。通过...

    Yii 2文件下载

    4. **Gii**:这是一个代码生成工具,可以帮助快速生成CRUD(创建、读取、更新、删除)操作和其他基础代码。 5. **Bootstrap**和**jQuery**:可能已经预装,作为前端开发的基础框架。 6. **文档**:可能包含Yii 2.0的...

    php项目开发全程实录的光盘的 第三版源代码

    学习源代码,你可以理解变量声明、数据类型、控制结构(如if/else,switch)、循环(for,while,do/while)以及函数的使用。 2. **面向对象编程**:第三版可能加强了对面向对象编程的支持,包括类、对象、继承、...

    yii1.1.10 开发包(包含yii权威指南以及yii博客例子讲解)

    4. **安全防护**:Yii 提供了防止SQL注入、跨站脚本攻击(XSS)和其他安全威胁的措施。例如,它的输入验证和输出过滤功能可以帮助保护应用免受攻击。 5. **身份认证和授权**:Yii 内置了RBAC(角色基础的访问控制)...

    Yii权威指南思维导图

    Yii采用MVC(Model-View-Controller)设计模式,这是Web应用开发中最常用的设计模式之一。在Yii中,Model负责处理数据和业务逻辑,View负责展示数据,而Controller则协调Model和View,处理用户请求并生成响应。 类...

Global site tag (gtag.js) - Google Analytics