别名是底层BaseYii提供的功能,涉及到的函数都是静态的,Yii类与BaseYii的关系是继承关系,源码为
class Yii extends \yii\BaseYii
{
}
可以设置别名,如
Yii::setAlias("@a","aaaa");
Yii::setAlias("@a/b","aaaa/bbb");
Yii::setAlias("@c","@a/u");
涉及的方法为
public static $aliases = ['@yii' => __DIR__];
public static function setAlias($alias, $path)
{
//可见第一个参数是否是@开头无所谓,即使没有@开头也会被强制加上
if (strncmp($alias, '@', 1)) {
$alias = '@' . $alias;
}
$pos = strpos($alias, '/');
$root = $pos === false ? $alias : substr($alias, 0, $pos);
if ($path !== null) { //创建别名操作
//别名的值是否还包含别名
$path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
//如果要创建的别名不存在
if (!isset(static::$aliases[$root])) {
if ($pos === false) {
static::$aliases[$root] = $path;
} else {
static::$aliases[$root] = [$alias => $path];
}
} elseif (is_string(static::$aliases[$root])) { //要创建的别名存在
if ($pos === false) {
static::$aliases[$root] = $path;
} else {
static::$aliases[$root] = [
$alias => $path,
$root => static::$aliases[$root],
];
}
} else { //要创建的别名存在
static::$aliases[$root][$alias] = $path;
krsort(static::$aliases[$root]);
}
} elseif (isset(static::$aliases[$root])) { //删除别名操作
if (is_array(static::$aliases[$root])) {
unset(static::$aliases[$root][$alias]);
} elseif ($pos === false) {
unset(static::$aliases[$root]);
}
}
}
根据源码,如
Yii::setAlias("@ab","abc");
Yii::setAlias("@ab/x","123");
var_dump(Yii::$aliases);
首先会创建一个@ab的别名,值为abc;
array (size=1)
'@ab' => string 'abc' (length=3)
然后存入$ab/x别名,底层的会将存@ab的结构改为数组
array (size=1)
'@ab' =>
array (size=2)
'@ab/x' => string '123' (length=3)
'@ab' => string 'abc' (length=3)
如果存入操作为
Yii::setAlias("@ab/x","abc");
Yii::setAlias("@ab/y","123");
var_dump(Yii::$aliases);
那么底层的结构为
array (size=1)
'@ab' =>
array (size=2)
'@ab/y' => string '123' (length=3)
'@ab/x' => string 'abc' (length=3)
删除一个别名也是setAlias
Yii::setAlias("@a",123); //创建别名
Yii::setAlias("@a"); //删除别名
取出别名的操作为getAlias
public static function getAlias($alias, $throwException = true)
{
//取出别名的第一个参数需要使用@开头
if (strncmp($alias, '@', 1)) {
// not an alias
return $alias;
}
$pos = strpos($alias, '/');
$root = $pos === false ? $alias : substr($alias, 0, $pos);
//判断根别名是否存在
if (isset(static::$aliases[$root])) {
if (is_string(static::$aliases[$root])) {
return $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos);
}
foreach (static::$aliases[$root] as $name => $path) {
if (strpos($alias . '/', $name . '/') === 0) {
return $path . substr($alias, strlen($name));
}
}
}
//如果查找不到别名则异常
if ($throwException) {
throw new InvalidArgumentException("Invalid path alias: $alias");
}
return false;
}
如
Yii::setAlias("@a/b","123");
$res = Yii::getAlias("@a/b/ccc"); //123/ccc
yii是依赖于composer的,composer是有自动加载机制的,Yii在composer的类自动加载基础上又做了一层自己的加载机制
class Yii extends \yii\BaseYii
{
}
spl_autoload_register(['Yii', 'autoload'], true, true);
Yii::$classMap = require __DIR__ . '/classes.php';
spl_autoload_register底层是一个队列,可以注册多个加载机制,第三个参数为true表示将这个队列放在最前面
所以yii的加载机制为
- 先用自己的类加载机制
- 自己的找不到就用composer的类加载机制 Yii使用了classMap机制类来做类与文件路径的映射,这种加载机制非常快,但是缺点是代码量非常大
return [
'yii\base\Action' => YII2_PATH . '/base/Action.php',
'yii\base\ActionEvent' => YII2_PATH . '/base/ActionEvent.php',
'yii\base\ActionFilter' => YII2_PATH . '/base/ActionFilter.php',
'yii\base\Application' => YII2_PATH . '/base/Application.php',
'yii\base\ArrayAccessTrait' => YII2_PATH . '/base/ArrayAccessTrait.php',
'yii\base\Arrayable' => YII2_PATH . '/base/Arrayable.php',
'yii\base\ArrayableTrait' => YII2_PATH . '/base/ArrayableTrait.php',
'yii\base\BaseObject' => YII2_PATH . '/base/BaseObject.php',
'yii\base\Behavior' => YII2_PATH . '/base/Behavior.php',
'yii\base\BootstrapInterface' => YII2_PATH . '/base/BootstrapInterface.php',
'yii\base\Component' => YII2_PATH . '/base/Component.php',
'yii\base\Configurable' => YII2_PATH . '/base/Configurable.php',
'yii\base\Controller' => YII2_PATH . '/base/Controller.php',
'yii\base\DynamicContentAwareInterface' => YII2_PATH . '/base/DynamicContentAwareInterface.php',
'yii\base\DynamicContentAwareTrait' => YII2_PATH . '/base/DynamicContentAwareTrait.php',
'yii\base\DynamicModel' => YII2_PATH . '/base/DynamicModel.php',
'yii\base\ErrorException' => YII2_PATH . '/base/ErrorException.php',
'yii\base\ErrorHandler' => YII2_PATH . '/base/ErrorHandler.php',
'yii\base\Event' => YII2_PATH . '/base/Event.php',
...
底层autoload逻辑为
public static function autoload($className)
{
if (isset(static::$classMap[$className])) { //如果在classMap中存在
$classFile = static::$classMap[$className];
if ($classFile[0] === '@') { //如果这个类的文件地址是一个别名,则获取这个别名对应的值
$classFile = static::getAlias($classFile);
}
} elseif (strpos($className, '\\') !== false) { //如果className不包含\\,则使用别名找对应的值
$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?");
}
}