Yii框架分析(一)入口脚本index.php的启动过程剖析
1. 启动 网站的唯一入口程序 index.php : $yii=dirname(__FILE__)./../framework/yii.php;$config=dirname(__FILE__)./protected/config/main.php;// remove the following line when in production modedefined(YII_DEBUG) or define(YII_DEBUG,true);requi
1. 启动
网站的唯一入口程序 index.php :
$yii=dirname(__FILE__).’/../framework/yii.php’; $config=dirname(__FILE__).’/protected/config/main.php’; // remove the following line when in production mode defined(‘YII_DEBUG’) or define(‘YII_DEBUG’,true); require_once($yii); Yii::createWebApplication($config)->run();
上面的require_once($yii) 引用出了后面要用到的全局类Yii,Yii类是YiiBase类的完全继承:
class Yii extends YiiBase { }
系统的全局访问都是通过Yii类(即YiiBase类)来实现的,Yii类的成员和方法都是static类型。
2. 类加载
Yii利用PHP5提供的spl库来完成类的自动加载。在YiiBase.php 文件结尾处
spl_autoload_register(array(‘YiiBase’,'autoload’));
将YiiBase类的静态方法autoload 注册为类加载器。 PHP autoload 的简单原理就是执行 new 创建对象或通过类名访问静态成员时,系统将类名传递给被注册的类加载器函数,类加载器函数根据类名自行找到对应的类文件并include 。
下面是YiiBase类的autoload方法:
public static function autoload($className) { // use include so that the error PHP file may appear if(isset(self::$_coreClasses[$className])) include(YII_PATH.self::$_coreClasses[$className]); else if(isset(self::$_classes[$className])) include(self::$_classes[$className]); else include($className.’.php’); }
可以看到YiiBase的静态成员$_coreClasses 数组里预先存放着Yii系统自身用到的类对应的文件路径:
private static $_coreClasses=array( ‘CApplication’ => ‘/base/CApplication.php’, ‘CBehavior’ => ‘/base/CBehavior.php’, ‘CComponent’ => ‘/base/CComponent.php’, … )
非 coreClasse 的类注册在YiiBase的$_classes 数组中:
private static $_classes=array();
其他的类需要用Yii::import()将类路径导入PHP include paths 中,直接
include($className.’.php’)
3. CWebApplication的创建
回到前面的程序入口的 Yii::createWebApplication($config)->run();
public static function createWebApplication($config=null) { return new CWebApplication($config); }
现在autoload机制开始工作了。
当系统 执行 new CWebApplication() 的时候,会自动
include(YII_PATH.’/base/CApplication.php’)
将main.php里的配置信息数组$config传递给CWebApplication创建出对象,并执行对象的run() 方法启动框架。
CWebApplication类的继承关系
CWebApplication -> CApplication -> CModule -> CComponent
$config先被传递给CApplication的构造函数
public function __construct($config=null) { Yii::setApplication($this); // set basePath at early as possible to avoid trouble if(is_string($config)) $config=require($config); if(isset($config['basePath'])) { $this->setBasePath($config['basePath']); unset($config['basePath']); } else $this->setBasePath(‘protected’); Yii::setPathOfAlias(‘application’,$this->getBasePath()); Yii::setPathOfAlias(‘webroot’,dirname($_SERVER['SCRIPT_FILENAME'])); $this->preinit(); $this->initSystemHandlers(); $this->registerCoreComponents(); $this->configure($config); $this->attachBehaviors($this->behaviors); $this->preloadComponents(); $this->init(); }
Yii::setApplication($this); 将自身的实例对象赋给Yii的静态成员$_app,以后可以通过 Yii::app() 来取得。
后面一段是设置CApplication 对象的_basePath ,指向 proteced 目录。
Yii::setPathOfAlias(‘application’,$this->getBasePath()); Yii::setPathOfAlias(‘webroot’,dirname($_SERVER['SCRIPT_FILENAME']));
设置了两个系统路径别名 application 和 webroot,后面再import的时候可以用别名来代替实际的完整路径。别名配置存放在YiiBase的 $_aliases 数组中。
$this->preinit();
预初始化。preinit()是在 CModule 类里定义的,没有任何动作。
$this->initSystemHandlers() 方法内容:
/** * Initializes the class autoloader and error handlers. */ 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()); }
设置系统exception_handler和 error_handler,指向对象自身提供的两个方法。
4. 注册核心组件
$this->registerCoreComponents();
代码如下:
protected function registerCoreComponents() { parent::registerCoreComponents(); $components=array( ‘urlManager’=>array( ‘class’=>’CUrlManager’, ), ‘request’=>array( ‘class’=>’CHttpRequest’, ), ‘session’=>array( ‘class’=>’CHttpSession’, ), ‘assetManager’=>array( ‘class’=>’CAssetManager’, ), ‘user’=>array( ‘class’=>’CWebUser’, ), ‘themeManager’=>array( ‘class’=>’CThemeManager’, ), ‘authManager’=>array( ‘class’=>’CPhpAuthManager’, ), ‘clientScript’=>array( ‘class’=>’CClientScript’, ), ); $this->setComponents($components); }
注册了几个系统组件(Components)。
Components 是在 CModule 里定义和管理的,主要包括两个数组
private $_components=array();
private $_componentConfig=array();
每个 Component 都是 IApplicationComponent接口的实例,Componemt的实例存放在$_components 数组里,相关的配置信息存放在$_componentConfig数组里。配置信息包括Component 的类名和属性设置。
CWebApplication 对象注册了以下几个Component:urlManager,request,session,assetManager,user,themeManager,authManager,clientScript。
CWebApplication的parent 注册了以下几个Component:coreMessages,db,messages,errorHandler,securityManager,statePersister。
Component 在YiiPHP里是个非常重要的东西,它的特征是可以通过 CModule 的 __get() 和 __set() 方法来访问。 Component 注册的时候并不会创建对象实例,而是在程序里被第一次访问到的时候,由CModule 来负责(实际上就是 Yii::app())创建。
5. 处理 $config 配置
继续, $this->configure($config);
configure() 还是在CModule 里:
public function configure($config) { if(is_array($config)) { foreach($config as $key=>$value) $this->$key=$value; } }
实际上是把$config数组里的每一项传给 CModule 的 父类 CComponent __set() 方法。
public function __set($name,$value) { $setter=’set’.$name; if(method_exists($this,$setter)) $this->$setter($value); 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); } 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))); }
我们来看看:
if(method_exists($this,$setter))
根据这个条件,$config 数组里的basePath, params, modules, import, components 都被传递给相应的 setBasePath(), setParams() 等方法里进行处理。
6、$config 之 import
其中 import 被传递给 CModule 的 setImport:
public function setImport($aliases) { foreach($aliases as $alias) Yii::import($alias); }
Yii::import($alias)里的处理:
public static function import($alias,$forceInclude=false) { // 先判断$alias是否存在于YiiBase::$_imports[] 中,已存在的直接return, 避免重复import。 if(isset(self::$_imports[$alias])) // previously imported return self::$_imports[$alias]; // $alias类已定义,记入$_imports[],直接返回 if(class_exists($alias,false)) return self::$_imports[$alias]=$alias; // 类似 urlManager 这样的已定义于$_coreClasses[]的类,或不含.的直接类名,记入$_imports[],直接返回 if(isset(self::$_coreClasses[$alias]) || ($pos=strrpos($alias,’.'))===false) // a simple class name { self::$_imports[$alias]=$alias; if($forceInclude) { if(isset(self::$_coreClasses[$alias])) // a core class require(YII_PATH.self::$_coreClasses[$alias]); else require($alias.’.php’); } return $alias; } // 产生一个变量 $className,为$alias最后一个.后面的部分 // 这样的:’x.y.ClassNamer’ // $className不等于 ‘*’, 并且ClassNamer类已定义的, ClassNamer’ 记入 $_imports[],直接返回 if(($className=(string)substr($alias,$pos+1))!==’*’ && class_exists($className,false)) return self::$_imports[$alias]=$className; // 取得 $alias 里真实的路径部分并且路径有效 if(($path=self::getPathOfAlias($alias))!==false) { // $className!==’*',$className 记入 $_imports[] if($className!==’*') { self::$_imports[$alias]=$className; if($forceInclude) require($path.’.php’); else self::$_classes[$className]=$path.’.php’; return $className; } // $alias是’system.web.*’这样的已*结尾的路径,将路径加到include_path中 else // a directory { set_include_path(get_include_path().PATH_SEPARATOR.$path); 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))); }
7. $config 之 components
$config 数组里的 $components 被传递给CModule 的setComponents($components)
public function setComponents($components) { foreach($components as $id=>$component) { 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; } }
$component是IApplicationComponen的实例的时候,直接赋值:
$this->setComponent($id,$component),
public function setComponent($id,$component) { $this->_components[$id]=$component; if(!$component->getIsInitialized()) $component->init(); }
如果$id已存在于_componentConfig[]中(前面注册的coreComponent),将$component 属性加进入。
其他的component将component属性存入_componentConfig[]中。
8. $config 之 params
这个很简单
public function setParams($value) { $params=$this->getParams(); foreach($value as $k=>$v) $params->add($k,$v); }
configure 完毕!
9. attachBehaviors
$this->attachBehaviors($this->behaviors);
空的,没动作
预创建组件对象
$this->preloadComponents();
protected function preloadComponents() { foreach($this->preload as $id) $this->getComponent($id); }
getComponent() 判断_components[] 数组里是否有 $id的实例,如果没有,就根据_componentConfig[$id]里的配置来创建组件对象,调用组件的init()方法,然后存入_components[$id]中。
10. init()
$this->init();
函数内:$this->getRequest();
创建了Reques 组件并初始化。
11. run()
public function run() { $this->onBeginRequest(new CEvent($this)); $this->processRequest(); $this->onEndRequest(new CEvent($this)); }

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Evaluating the cost/performance of commercial support for a Java framework involves the following steps: Determine the required level of assurance and service level agreement (SLA) guarantees. The experience and expertise of the research support team. Consider additional services such as upgrades, troubleshooting, and performance optimization. Weigh business support costs against risk mitigation and increased efficiency.

The learning curve of a PHP framework depends on language proficiency, framework complexity, documentation quality, and community support. The learning curve of PHP frameworks is higher when compared to Python frameworks and lower when compared to Ruby frameworks. Compared to Java frameworks, PHP frameworks have a moderate learning curve but a shorter time to get started.

The lightweight PHP framework improves application performance through small size and low resource consumption. Its features include: small size, fast startup, low memory usage, improved response speed and throughput, and reduced resource consumption. Practical case: SlimFramework creates REST API, only 500KB, high responsiveness and high throughput

According to benchmarks, for small, high-performance applications, Quarkus (fast startup, low memory) or Micronaut (TechEmpower excellent) are ideal choices. SpringBoot is suitable for large, full-stack applications, but has slightly slower startup times and memory usage.

Writing clear and comprehensive documentation is crucial for the Golang framework. Best practices include following an established documentation style, such as Google's Go Coding Style Guide. Use a clear organizational structure, including headings, subheadings, and lists, and provide navigation. Provides comprehensive and accurate information, including getting started guides, API references, and concepts. Use code examples to illustrate concepts and usage. Keep documentation updated, track changes and document new features. Provide support and community resources such as GitHub issues and forums. Create practical examples, such as API documentation.

Choose the best Go framework based on application scenarios: consider application type, language features, performance requirements, and ecosystem. Common Go frameworks: Gin (Web application), Echo (Web service), Fiber (high throughput), gorm (ORM), fasthttp (speed). Practical case: building REST API (Fiber) and interacting with the database (gorm). Choose a framework: choose fasthttp for key performance, Gin/Echo for flexible web applications, and gorm for database interaction.

Java framework learning roadmap for different fields: Web development: SpringBoot and PlayFramework. Persistence layer: Hibernate and JPA. Server-side reactive programming: ReactorCore and SpringWebFlux. Real-time computing: ApacheStorm and ApacheSpark. Cloud Computing: AWS SDK for Java and Google Cloud Java.

There are five misunderstandings in Go framework learning: over-reliance on the framework and limited flexibility. If you don’t follow the framework conventions, the code will be difficult to maintain. Using outdated libraries can cause security and compatibility issues. Excessive use of packages obfuscates code structure. Ignoring error handling leads to unexpected behavior and crashes.
