Yii應用的入口腳本引用出了Yii類,Yii類的定義:
class Yii extends YiiBase { }
由yiic創建的應用裡Yii類只是YiiBase類的“馬甲”,我們也可以根據需求定制自己的Yii類。
Yii(即YiiBase)是一個“helper class”,為整個應用提供靜態和全域存取入口。
Yii類別的幾個靜態成員:
$_aliases : 存放系統的別名對應的真實路徑
$_imports :
$_classes :
$_includePaths php include paths
_$app 物件透過存取到
$_logger : 系統日誌物件
$_app 物件由Yii::createWebApplication() 方法建立。
類別自動載入
Yii基於php5的autoload機制來提供類別的自動載入功能,自動載入器為YiiBase類別的靜態方法autoload()。
當程式中以new建立物件或存取到類別的靜態成員,php將類別名稱傳遞給類別載入器,由類別載入器完成類別檔案的include。
autoload機制實現了類別的“按需導入”,就是系統存取到類別時才include類別的檔案。
YiiBase類別的靜態成員$_coreClasses 裡預先存放了Yii自身的核心類別名稱於對應的類別檔案路徑。其他的Yii應用程式中所使用的類別可以用Yii::import() 導入,Yii::import()將單一類別的與對應類別檔案存放於$_classes中,以*通配符表示的路徑加入php include_path中。被Yii::import()導入的類別檔案或目錄都會記入$_imports中,避免多次導入。
/* Yii::import() * $alias: 要导入的类名或路径 * $forceInclude false:只导入不include类文件,true则导入并include类文件 */ 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) || interface_exists($alias,false)) return self::$_imports[$alias]=$alias; // 已定义于$_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) || interface_exists($className,false))) return self::$_imports[$alias]=$className; // $alias里含有别名,并转换真实路径成功 if(($path=self::getPathOfAlias($alias))!==false) { // 不是以*结尾的路径(单类) if($className!==’*') { self::$_imports[$alias]=$className; if($forceInclude) require($path.’.php’); else // 类名与真实路径记入$_classes数组 self::$_classes[$className]=$path.’.php’; return $className; } // $alias是’system.web.*’这样的已*结尾的路径,将路径加到include_path中 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); set_include_path(‘.’.PATH_SEPARATOR.implode(PATH_SEPARATOR,self::$_includePaths)); 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))); }
然後看看 YiiBase::autoload() 函數的處理:
public static function autoload($className) { // $_coreClasses中配置好的类直接引入 if(isset(self::$_coreClasses[$className])) include(YII_PATH.self::$_coreClasses[$className]); // $_classes 中登记的单类直接引入 else if(isset(self::$_classes[$className])) include(self::$_classes[$className]); else { // 其他的认为文件路径以记入 include_path 里,以$className.’.php’直接引入 include($className.’.php’); return class_exists($className,false) || interface_exists($className,false); } return true; }
系統設定檔裡的 import 項目裡的類別或路徑在腳本啟動中會自動導入。使用者應用程式裡個別類別需要引入的類別可以在類別定義前加入 Yii::import() 語句。
應用元件管理
前面提到Yii的CComponent類別提供了元件的屬性、事件、行為的存取接口,而CComponent的子類別CModule更提供了應用元件(application components)的管理。
應用元件必須是IApplicationComponent介面的實例,需要實作介面的init()和getIsInitialized()方法。 init()會在應用元件初始化參數後被自動呼叫。
Yii本身的功能模組都是透過應用元件的方式來提供的,例如常見的 Yii::app()->user, Yii::app()->request 等。使用者也可以定義應用元件。
作為 Yii::app() 物件(CWebApplication)的父類,CModule提供了完整的元件生命週期管理,包括元件的建立、初始化、物件儲存等。
每個應用元件用一個字串名字來標識,透過CModule類別的__get() 方法來存取。
CModule類別的$_components[] 成員存放應用元件的物件實例($name => $object),$_componentConfig[] 裡存放應用元件的類別名稱和初始化參數。
使用應用元件的時候,先在$_componentConfig裡設定好元件的類別名稱和初始化參數,在第一次存取元件的時候,CModule會自動建立應用元件物件實例並初始化給定的參數,然後會呼叫應用組件的init()方法。
Yii::app()物件的類別CWebApplication及其父類別CApplication預先配置了系統本身用到的應用元件:urlManager, request, session, assetManager, user, themeManager, authManager, clientScript, coreMessages, db, messages, errorHandler, securityManager, statePersister。
我們可以再系統設定檔的components專案裡修改系統應用元件的參數或設定新的應用元件。
CModule並不負責應用元件實例的創建,而是由Yii::createComponent() 靜態方法來完成的。
createComponent()的參數$config 可以是類別名稱的字串或是儲存了類別名稱和初始化參數的陣列。
應用元件的設定
應用元件的設定儲存在系統$config變數中(config/main.php裡)的components項目裡:
// application components ‘components’=>array( ‘log’=>array( ‘class’=>’CLogRouter’, ‘routes’=>array( array( ‘class’=>’CFileLogRoute’, ‘levels’=>’error, warning’, ), ), ), ‘user’=>array( // enable cookie-based authentication ‘allowAutoLogin’=>true, ), ),
$config裡的components項目在CApplication的建構子裡被處理:
$this->configure($config);
configure()函數的處理很簡單:
public function configure($config) { if(is_array($config)) { foreach($config as $key=>$value) $this->$key=$value; } }
$config裡的每一項當做屬性傳給$_app物件的setXXX()屬性設定方法,其中'components'項目在CWebApplication的CModule的父類別setComponents()處理。
setComponents() 將’components’項目裡的類別名稱及初始化參數存放到 $_componentConfig[]裡:
public function setComponents($components) { // $config 里的’components’每一项 foreach($components as $id=>$component) { if($component instanceof IApplicationComponent) $this->setComponent($id,$component); // $_componentConfig里已经存在配置,合并$component else if(isset($this->_componentConfig[$id])) $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component); // 在$_componentConfig里新建项目 else $this->_componentConfig[$id]=$component; } }
應用元件的存取
CModule类重载了CComponent的__get()方法,优先访问应用组件对象。
public function __get($name) { if($this->hasComponent($name)) return $this->getComponent($name); else return parent::__get($name); }
hasComponent() 判断$_components[]中是否已存在组件实例,或$_componentConfig[]中存在组件配置信息。
public function hasComponent($id) { return isset($this->_components[$id]) || isset($this->_componentConfig[$id]); }
getComponent() 判断组件实例已经存在于$_components[]中,则直接返回对象。
否则根据$_componentConfig[]里的组件配置数据调用 Yii::createComponent() 来创建组件,并将对象存入$_components[]中然后返回。
public function getComponent($id,$createIfNull=true) { if(isset($this->_components[$id])) return $this->_components[$id]; else if(isset($this->_componentConfig[$id]) && $createIfNull) { $config=$this->_componentConfig[$id]; unset($this->_componentConfig[$id]); if(!isset($config['enabled']) || $config['enabled']) { Yii::trace(“Loading \”$id\” application component”,’system.web.CModule’); unset($config['enabled']); $component=Yii::createComponent($config); $component->init(); return $this->_components[$id]=$component; } } }
应用组件的创建
Yii::createComponent() 来完成应用组件的创建
public static function createComponent($config) { if(is_string($config)) { $type=$config; $config=array(); } else if(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]); else if($n===3) $object=new $type($args[1],$args[2]); else if($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; }
以上就是Yii框架分析(三)——类加载机制及应用组件的管理、配置、访问、创建的内容,更多相关内容请关注PHP中文网(www.php.cn)!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版
SublimeText3 Linux最新版

Dreamweaver CS6
視覺化網頁開發工具

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中