PHP的Yii框架中YiiBase入口類的擴(kuò)展寫法示例
通過yiic.php自動(dòng)創(chuàng)建一個(gè)應(yīng)用后,入口文件初始代碼如下:
<?php // change the following paths if necessary $yii=dirname(__FILE__).'/../yii/framework/yii.php'; $config=dirname(__FILE__).'/protected/config/main.php'; // remove the following lines when in production mode defined('YII_DEBUG') or define('YII_DEBUG',true); // specify how many levels of call stack should be shown in each log message defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3); require_once($yii); Yii::createWebApplication($config)->run();
其中第三行引入了一個(gè)yii.php的文件,這個(gè)可以在yii核心目錄里的framework/下找到,這個(gè)文件中定義了一個(gè)Yii類,并且繼承了YiiBase類。
代碼如下
require(dirname(__FILE__).'/YiiBase.php'); /** * Yii is a helper class serving common framework functionalities. * * It encapsulates {@link YiiBase} which provides the actual implementation. * By writing your own Yii class, you can customize some functionalities of YiiBase. * * @author Qiang Xue <qiang.xue@gmail.com> * @package system * @since 1.0 */ class Yii extends YiiBase { }
而
Yii::createWebApplication
這個(gè)方法實(shí)際上是在YiiBase父類中定義的,所以,Yii為我們預(yù)留了擴(kuò)展的可能。我們只需要在yii.php中添加我們想要擴(kuò)展的方法即可,在項(xiàng)目中直接使用 Yii::方法名() 調(diào)用。
為了將項(xiàng)目代碼和核心目錄完全分離,我個(gè)人覺得在項(xiàng)目目錄下使用另外一個(gè)yii.php來替代從核心目錄中包含yii.php更加好。
這里我用了更加極端的方法,我直接將yii這個(gè)類定義在了入口文件,并擴(kuò)展了一個(gè)全局工廠函數(shù) instance()方法,請(qǐng)看代碼:
<?php // change the following paths if necessary $yii=dirname(__FILE__).'/../yii/framework/YiiBase.php'; $config=dirname(__FILE__).'/protected/config/main.php'; // remove the following lines when in production mode defined('YII_DEBUG') or define('YII_DEBUG',true); // specify how many levels of call stack should be shown in each log message defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3); require_once($yii); //擴(kuò)展基類 class Yii extends YiiBase{ /** * 全局?jǐn)U展方法:工廠函數(shù) * @param type $alias 類庫別名 */ static function instance($alias){ static $_class_ = array(); $key = md5($alias); if(!isset($_class_[$key])){ $_class_[$key] = self::createComponent($alias); } return $_class_[$key]; } } Yii::createWebApplication($config)->run();
這個(gè)類是在最后一行Yii::createWebApplication()之前定義的,以保證Yii類能正常使用(不要把這個(gè)類放在文件末尾,會(huì)出錯(cuò)。)
在項(xiàng)目中任何地方,使用$obj = Yii::instance($alias);去實(shí)例化一個(gè)類,并且是單例模式。
YiiBase中的兩個(gè)比較重要的方法 (import,autoload)
然后看看YiiBase中的import方法就知道這些靜態(tài)變量是干嘛用的了:
/* Yii::import() * $alias: 要導(dǎo)入的類名或路徑 * $forceInclude false:只導(dǎo)入不include類文件,true則導(dǎo)入并include類文件 */ public static function import($alias, $forceInclude = false){ //Yii把所有的依賴放入到這個(gè)全局的$_imports數(shù)組中,名字不能重復(fù) //如果當(dāng)前依賴已經(jīng)被引入過了,那么直接返回 if (isset(self::$_imports[$alias])) { return self::$_imports[$alias]; } //class_exists和interface_exists方法的第二個(gè)參數(shù)的值為false表示不autoload if (class_exists($alias, false) || interface_exists($alias, false)) { return self::$_imports[$alias] = $alias; } //如果傳進(jìn)來的是一個(gè)php5.3版本的命名空間格式的類(例如:\a\b\c.php) if (($pos = strrpos($alias, '\\')) !== false) { //$namespace = a.b $namespace = str_replace('\\', '.', ltrim(substr($alias, 0, $pos), '\\')); //判斷a.b這個(gè)路徑是否存在,或者a.b只是alias里面的一個(gè)鍵,調(diào)用該方法返回這個(gè)鍵對(duì)應(yīng)的值,比如'email' => realpath(__DIR__ . '/../vendor/cornernote/yii-email-module/email') 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 { // try to autoload the class with an autoloader if (class_exists($alias, true)) { return self::$_imports[$alias] = $alias; } else { throw new CException(Yii::t('yii', 'Alias "{alias}" is invalid. Make sure it points to an existing directory or file.', array('{alias}' => $namespace))); } } } if (($pos = strrpos($alias, '.')) === false) // a simple class name { // try to autoload the class with an autoloader if $forceInclude is true if ($forceInclude && (Yii::autoload($alias, true) || class_exists($alias, true))) { 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; } // $alias是'system.web.*'這樣的已*結(jié)尾的路徑,將路徑加到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); 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))); } }
是的,上面這個(gè)方法最后就把要加載的東西都放到$_imports,$_includePaths中去了。這就是Yii的import方法,好的,接下來我們看看autoload方法:
public static function autoload($className, $classMapOnly = false){ // use include so that the error PHP file may appear if (isset(self::$classMap[$className])) { include(self::$classMap[$className]); } elseif (isset(self::$_coreClasses[$className])) { include(YII_PATH . self::$_coreClasses[$className]); } elseif ($classMapOnly) { return false; } else { // include class file relying on include_path if (strpos($className, '\\') === false) // class without namespace { if (self::$enableIncludePath === false) { foreach (self::$_includePaths as $path) { $classFile = $path . DIRECTORY_SEPARATOR . $className . '.php'; if (is_file($classFile)) { include($classFile); if (YII_DEBUG && basename(realpath($classFile)) !== $className . '.php') { throw new CException(Yii::t('yii', 'Class name "{class}" does not match class file "{file}".', array( '{class}' => $className, '{file}' => $classFile, ))); } break; } } } else { include($className . '.php'); } } else // class name with namespace in PHP 5.3 { $namespace = str_replace('\\', '.', ltrim($className, '\\')); if (($path = self::getPathOfAlias($namespace)) !== false) { include($path . '.php'); } else { return false; } }
return class_exists($className, false) || interface_exists($className, false); } return true;}
config文件中的 import 項(xiàng)里的類或路徑在腳本啟動(dòng)中會(huì)被自動(dòng)導(dǎo)入。用戶應(yīng)用里個(gè)別類需要引入的類可以在類定義前加入 Yii::import() 語句。
相關(guān)文章
PHP中使用xmlreader讀取xml數(shù)據(jù)示例
這篇文章主要介紹了PHP中使用xmlreader讀取xml數(shù)據(jù)示例,本文示例相對(duì)簡單,只包含了一個(gè)讀取功能,需要的朋友可以參考下2014-12-12PHP基于工廠模式實(shí)現(xiàn)的計(jì)算器實(shí)例
這篇文章主要介紹了PHP基于工廠模式實(shí)現(xiàn)的計(jì)算器,實(shí)例分析了php工廠模式的實(shí)現(xiàn)原理與應(yīng)用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07約瑟夫環(huán)問題的PHP實(shí)現(xiàn) 使用PHP數(shù)組內(nèi)部指針操作函數(shù)
約瑟夫環(huán)問題相信大家都已經(jīng)很熟悉了,一直想使用 PHP 來實(shí)現(xiàn)一下,琢磨了老半天的時(shí)間終于弄出來了,也許沒有網(wǎng)上的一些代碼實(shí)現(xiàn)的簡潔高效,但是畢竟是寫出來了~呵呵。2010-10-10