Yii2之類自動加載

  在yii中,程序中須要使用到的類無需事先加載其類文件,在使用的時候才自動定位類文件位置並加載之,這麼高效的運行方式得益於yii的類自動加載機制。php

  Yii的類自動加載實際上使用的是PHP的類自動加載,因此先來看看PHP的類自動加載。在PHP中,當程序中使用的類未加載時,在報錯以前會先調用魔術方法__autoload(),因此咱們能夠重寫__autoload()方法,定義當一個類找不到的時候怎麼去根據類名稱找到對應的文件並加載它。其中__autoload()方法被稱爲類自動加載器。當咱們須要多個類自動加載器的時候,咱們可使用spl_autoload_register()方法代替__autoload()來註冊多個類自動加載器,這樣就至關於有多個__autoload()方法。spl_autoload_register()方法會把全部註冊的類自動加載器存入一個隊列中,你能夠經過設置它的第三個參數爲true來指定某個加載器放到隊列的最前面以確保它最早被調用。Yii的類自動加載機制就是基於spl_autoload_register()方法的。web

  Yii的類自動加載機制要從它的入口文件index.php提及了,該文件源碼以下:bootstrap

<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);//運行模式
defined('YII_ENV') or define('YII_ENV', 'dev');//運行環境

require(__DIR__ . '/../../vendor/autoload.php');//composer的類自動加載文件
require(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');//yii的工具類文件(包含了yii類自動加載)
require(__DIR__ . '/../../common/config/bootstrap.php');//主要用於執行一些yii應用引導的代碼
require(__DIR__ . '/../config/bootstrap.php');

$config = yii\helpers\ArrayHelper::merge(
    require(__DIR__ . '/../../common/config/main.php'),
    require(__DIR__ . '/../../common/config/main-local.php'),
    require(__DIR__ . '/../config/main.php'),
    require(__DIR__ . '/../config/main-local.php')
);

(new yii\web\Application($config))->run();

  文件中第5、六行代碼分別引入了composer的類自動加載文件和yii的工具類文件Yii.phpYii.php文件源碼以下:數組

require(__DIR__ . '/BaseYii.php');

class Yii extends \yii\BaseYii
{
}

spl_autoload_register(['Yii', 'autoload'], true, true);//註冊yii的類自動加載器
Yii::$classMap = require(__DIR__ . '/classes.php');//引入類名到類文件路徑的映射
Yii::$container = new yii\di\Container();

  這個文件定義了Yii類繼承自\yii\BaseYii,代碼的第8行引入了classes.php文件,該文件源碼:yii2

return [
  'yii\base\Action' => YII2_PATH . '/base/Action.php',
  'yii\base\ActionEvent' => YII2_PATH . '/base/ActionEvent.php',

   ....//省略n多元素    

  'yii\widgets\Pjax' => YII2_PATH . '/widgets/Pjax.php',
  'yii\widgets\PjaxAsset' => YII2_PATH . '/widgets/PjaxAsset.php',
  'yii\widgets\Spaceless' => YII2_PATH . '/widgets/Spaceless.php',
];

  經過查看其源碼能夠看到,這個文件返回了一個從類名稱到類文件路徑的映射數組。這個數組被賦值給Yii::$classMap。代碼的第7行調用了spl_autoload_register()方法註冊了一個類自動加載器,這個類加載器爲Yii::autoload(),這就是yii的類加載器了。同時這裏經過把spl_autoload_register()方法第三個參數賦值爲true,把yii的類加載器放在了加載器隊列的最前面,因此當訪問一個未加載的類的時候,yii的類自動加載器會最早被調用。composer

  下面咱們就來看看yii的類自動加載器Yii::autoload()到底作了些什麼,這個方法實際上在yii\BaseYii類中,源碼以下:less

/**
 * 類自動加載器
 * @param type $className:要加載的類的名稱
 * @return type
 * @throws UnknownClassException
 */
public static function autoload($className)
{
	if (isset(static::$classMap[$className])) {//要加載的類在 類名=>類文件路徑 映射中找到
		$classFile = static::$classMap[$className];
		if ($classFile[0] === '@') {//若類文件路徑使用了別名,進行別名解析得到完整路徑
			$classFile = static::getAlias($classFile);
		}
	} elseif (strpos($className, '\\') !== false) {//類名須要包含'\'才符合規範
		$classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false);//進行別名解析(說明類名必須以有效的根別名打頭)
		if ($classFile === false || !is_file($classFile)) {
			return;
		}
	} else {
		return;
	}

	include($classFile);//引入須要加載的類文件

	if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) {
		throw new UnknownClassException("Unable to find '$className' in file: $classFile. Namespace missing?");
	}
}

  這個方法首先會根據須要加載的類的名稱去Yii::$classMap這個映射數組中查找,若存在則引入對應的類文件,不存在則進行別名解析獲得完整文件路徑,這裏也說明若使用的類不在YII::$classMap中事先定義,則類名必須以有效的根別名打頭,不然沒法找到對應文件。yii

  就這樣,在yii中無需在程序中事先加載一大堆可能會使用到的類文件,當使用到某個類的時候,yii的類自動加載器就會自動進行加載了,高效又便捷!工具

相關文章
相關標籤/搜索