在php中,想要实例化一个类,必须先在实例化之前加载类:
require ..../class1.php 或者 include ..../class1.php
require ..../class2.php 或者 include ..../class2.php
$try = new class1;
$try1 = new class2;
这样的做法使即时不会马上用到的类都要一次性全部加载,导致效率下降
php5以后,引入函数spl_autoload_register(),现在大多数框架都有使用,使用spl_autoload_register之前需要先设置一个自动装载函数,规定了参数与实际类路径的关系及加载方式。
function autoload($class){
require (路径/class.php);
}
然后将这个函数注册到spl函数中
spl_autoload_register(“autoload”);
这样,当实例化一个未加载的类时,会触发spl_autoload_register函数,进而触发autoload函数,将class加载,这就是所谓的类延迟加载。
Yii2中是如何使用自动加载的?这个先定位到入口文件的index.php中:
// comment out the following two lines when deployed to production
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
//Yii::setAlias('@common', '@app/common/');
$config = require(__DIR__ . '/../config/web.php');
(new yii\web\Application($config))->run();
autoload.php是第三方的类加载,只要保证Yii.php在最后面,就可以确保其可以将自己的autoloader插入到整个autoloder 栈的最前面,从而在需要时最先被调用。
再来看看Yii.php的
class Yii extends \yii\BaseYii
{
}
spl_autoload_register([‘Yii’, ‘autoload’], true, true);
Yii::$classMap = require(DIR . ‘/classes.php’);
Yii::$container = new yii\di\Container();
注册的是BaseYii.php中的autoload函数,然后Yii将 calsses.php 这个文件作为一个映射表保存到 Yii::$classMap 当中。这个映射表,保存了一系列的类名与其所在PHP文件的映射关系。
最后看一下auto函数的奥秘:
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?");
}
}
这个函数的大意就是看参数如果是一个字符串,就搜索看看有没有这个别名,找到对应路径,如果参数是一个路径,就直接找到路径,否则就报错!