Yii2 的自動載入分兩部分,一部分是 Composer 的自動載入機制,另一部分是 Yii2 架構自身的自動載入機制。
Composer自動載入
對於庫的自動載入資訊,Composer 產生了一個 vendor/autoload.php 檔案。你可以簡單的引入這個檔案,你會得到一個自動載入的支援。
在之前的文章,入口檔案的介紹中,我們可以看到如下內容:
// 引入 vendor 中的 autoload.php 檔案,會基於 composer 的機制自動載入類require(__DIR__ . '/../vendor/autoload.php');
因為這個系列主要是關於 Yii2 的,所以有關 Composer 自動載入機制就不在這裡詳細說明了。
可查閱資料:
- Composer 自動載入
- Composer 自動載入-參考
- Composer 中文官網
Yii2 架構的自動載入機制
Yii2 架構的自動載入是通過 spl_autoload_register 方法實現的。
在之前的文章,入口檔案的介紹中,我們可以看到如下內容:
// 引入 Yii 架構的檔案 Yii.phprequire(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
Yii.php 裡究竟是什麼內容?如何?了自動載入?
下面我們來看一下,Yii.php 的內容如下:
php/** * Yii bootstrap file. * * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */require(__DIR__ . '/BaseYii.php');/** * Yii is a helper class serving common framework functionalities. * * It extends from [[\yii\BaseYii]] which provides the actual implementation. * By writing your own Yii class, you can customize some functionalities of [[\yii\BaseYii]]. * * @author Qiang Xue * @since 2.0 */class Yii extends \yii\BaseYii{}/** * spl_autoload_register — 註冊給定的函數作為 __autoload 的實現 * * bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] ) * * 將函數註冊到SPL __autoload函數隊列中。如果該隊列中的函數尚未啟用,則啟用它們。 * 如果在你的程式中已經實現了__autoload()函數,它必須顯式註冊到__autoload()隊列中。 * 因為 spl_autoload_register()函數會將Zend Engine中的__autoload()函數取代為spl_autoload()或spl_autoload_call()。 * 如果需要多條 autoload 函數,spl_autoload_register() 滿足了此類需求。 * 它實際上建立了 autoload 函數的隊列,按定義時的順序逐個執行。 * 相比之下, __autoload() 只可以定義一次。 * * autoload_function * 欲註冊的自動裝載函數。如果沒有提供任何參數,則自動註冊 autoload 的預設實現函數spl_autoload()。 * * throw * 此參數設定了 autoload_function 無法成功註冊時, spl_autoload_register()是否拋出異常。 * * prepend * 如果是 true,spl_autoload_register() 會添加函數到隊列之首,而不是隊列尾部。 * * Yii 註冊了 Yii 的 autoload 函數,實現自動載入, 其實現在 \yii\BaseYii 中 */spl_autoload_register(['Yii', 'autoload'], true, true);// 定義 Yii 核心的 class 的類名與檔案地址的 MapYii::$classMap = require(__DIR__ . '/classes.php');// 建立 Yii 的依賴注入的容器Yii::$container = new yii\di\Container();
其主要內容就是引入了 BaseYii.php 檔案,然後聲明了類 Yii,繼承了 BaseYii,然後註冊了 Yii (其實是 BaseYii)的 autoload 方法,去實現自動載入。之後又引入了Yii 核心類名與檔案地址一一對應的 Map,儲存到 Yii::$classMap 中。最後建立了一個 yii\di\Container 的執行個體,儲存到 Yii::$container 中。
可以看出實現自動載入的關鍵代碼是:
spl_autoload_register(['Yii', 'autoload'], true, true);
下面我們來看一下 BaseYii 中 autoload 方法的實現,其內容如下:
/** * Class autoload loader. * This method is invoked automatically when PHP sees an unknown class. * The method will attempt to include the class file according to the following procedure: * * 1. Search in [[classMap]]; * 2. If the class is namespaced (e.g. `yii\base\Component`), it will attempt * to include the file associated with the corresponding path alias * (e.g. `@yii/base/Component.php`); * * This autoloader allows loading classes that follow the [PSR-4 standard](http://www.php-fig.org/psr/psr-4/) * and have its top-level namespace or sub-namespaces defined as path aliases. * * Example: When aliases `@yii` and `@yii/bootstrap` are defined, classes in the `yii\bootstrap` namespace * will be loaded using the `@yii/bootstrap` alias which points to the directory where bootstrap extension * files are installed and all classes from other `yii` namespaces will be loaded from the yii framework directory. * * Also the [guide section on autoloading](guide:concept-autoloading). * * @param string $className the fully qualified class name without a leading backslash "\" * @throws UnknownClassException if the class does not exist in the class file */publicstaticfunction autoload($className) { // 自動載入類if (isset(static::$classMap[$className])) { // 如果 $classMap 中存在該類,就直接使用$classFile = static::$classMap[$className]; // 如果第一個字串為'@',就意味著對應的檔案地址是別名,就將它轉化成真實的檔案地址if ($classFile[0] === '@') { $classFile = static::getAlias($classFile); } } elseif (strpos($className, '\\') !== false) { // 如果存在'\\',就意味著含有 namespace,可以拼成別名,再根據別名擷取真實的檔案地址$classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false); // 沒取到真是檔案地址或者擷取的地址不是一個檔案,就返回空if ($classFile === false || !is_file($classFile)) { return; } } else { return; } // 引入該類的檔案include($classFile); // 如果是偵錯模式,而且 $className 即不是類,不是介面,也不是 trait,就拋出異常if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) { thrownew UnknownClassException("Unable to find '$className' in file: $classFile. Namespace missing?"); } }
其中,大家可能不太清楚 getAlias 方法,這個方法其實就是將 Yii2 中的別名轉化成真實的檔案地址,關於該方法的具體內容,之後會詳細講解。
舉幾個例子,協助大家理解一下。
如果 Yii::$classMap 的值如下:
Yii::$classMap = [ 'app/test/Test' => '/var/www/basic/webtest/Test.php'];
當你使用 ‘app/test/Test’ 類時,就會自動引入 '/var/www/basic/webtest/Test.php' 檔案,項目中的內容當然不是這個樣子的,這隻是個簡單的例子,便於大家理解。
在繼續上面的例子,如果你使用了‘yii\base\Component’ 類,它就會轉變成 ‘@yii/base/Component.php’ 別名,然後在根據別名擷取到它的檔案地址,引入進來。
以上就是 Yii2 的自動載入機制的基本內容~~
對 Yii2 源碼有興趣的同學可以關注項目 yii2-2.0.3-annotated,現在在上面已經添加了不少關於 Yii2 源碼的注釋,之後還會繼續添加~
有興趣的同學也可以參與進來,提交 Yii2 源碼的注釋。
以上就介紹了Yii2的深入學習--自動載入機制,包括了require,隊列,Exception方面的內容,希望對PHP教程有興趣的朋友有所協助。