目录:
1. 理解PSR4 规范
2. 理解composer autoload 的实现
3. 理解yii2 autoload的实现
4. yii2 autoload 与 composer autoload 的联系与区别
5. yii2 核心类的 加载 流程, classmap 作用及意义
6. yii2 container 类/对象 的作用,如何自定义自己的container类
7. yii2 路由规则类,路由管理类 特点,如何自定义自己的路由规则类。
8. 框架常用的函数,但平时写业务不常用的函数
9. Application 类
10. 异常处理的注册,及异常处理
11. 日志处理
参考博客:
vendor/yiisoft/yii2/classes.php 里边定义了 classMap
classMap 是 yii2 核心包 里边 的类的map; 像独立的yii2 包的类不在此数组内:如 yii\gii ; yii\debug
vendor/yiisoft/yii2/Yii.php
spl_autoload_register(['Yii', 'autoload'], true, true);
注意 第三个参数 true 表示优先 从 yii2 的 autoload 函数 去加载类,再尝试 用 composer 的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
*/
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?");
}
}
说明: 先从 classMap 中找,没有再看 @+className 的前缀 是否在 self::$aliases 数组中。
self:;$aliases 别名的路径设置 过程如下:
设置 @app 对应的路径
yii\web\Application->setBasePath()
其中: Yii::setAlias('@app', $this->getBasePath());
设置@vendor @bower @npm 对应的路径
yii\web\Application->preInit()
设置@runtime 对应的路径
yii\web\Application->preInit()
yii\web\Application->init()
的 bootstrap 中 设置 别名 @webroot @web 的路径值
parent::bootstrap 从 @vendor/yiisoft/extensions.php
来设置 另外的 extension 的 alias 的 路径值
有:@yii/bootstrap
@yii/swifmailer
@yii/faker
@yii/redis
@yii/elasticsearch
@yii\debug
@yii/gii
@yii/queue
@yii/queue
@yii/queue/amqp
@yii/queue/amqp_interop
@yii/queue/beanstalk
@yii/queue/db
@yii/queue/file
//….
@yii/mongodb
顺序:
composer 的autoload 先进行 spl_autoload_register 注册
再进行 yii2 autoload 的 spl_autoload_register 注册
找类时 先使用 yii2 autoload 函数 找,再使用 composer 的autoload 函数找
相同点: 都使用 include $file
快速找到yii2 core 类的 路径 ,可加快core 类 include 速度
可以 改变/classmap 数组的元素 value ; 也可以添加 一个 元素 如:
添加一个元素如:
spl_autoload_register(['Yii', 'autoload'], true, true);
Yii::$classMap = require __DIR__ . '/../vendor/yiisoft/yii2/classes.php';
Yii::$classMap['app\components\Container'] = __DIR__. '/../components/Container.php';
Yii::$container = new app\components\Container();
也可以改变 一个元素的 value :
spl_autoload_register(['Yii', 'autoload'], true, true);
Yii::$classMap = require __DIR__ . '/../vendor/yiisoft/yii2/classes.php';
Yii::$classMap['yii\di\Container'] = __DIR__. '/../components/Container.php';
Yii::$container = new yii\di\Container();
这种方式 可以达到的目的是: 完全替换 yii2 核心类 ,以满足自己改造的需求,
注意Container.php 中 namespace 和 核心类 要完全一样
通过这种方式 classes.php 中的 core 类 可以被完全替换。
作用: 1. 创建yii2 的其它类的对象, 2 创建用户的类的对象,并解决了依赖对象
原理 它 很早被实例化,其属性 被 Application 用 config 下相应的配置来 赋值
对它的改造: 1 是完全替换, 2是 自定义Container 类 来继承 yii2 核心的 container 类
container 的配置
config/container.php
'redisLua' => 'app\tool\RedisLua',
'redisLua' => app\tool\RedisLua::class,
'redisLua' => [
'app\tool\RedisLua',
[] //对应container->get(...) 中 params参数,是依赖
],
'redisLua' => [ //注意这样写报错!!! yii\base\InvalidConfigException
['app\tool\RedisLua'], //因为,这个元素要被解析为 define ,要么如上个写法是字符串,要么是数组当必须有 class=> '...',如下例子
[]
],
'redisLua' => [
[
'class' => 'app\tool\RedisLua',
'apcu' => true,
],
[]
],
'redisLua' => [
'class' => app\tool\RedisLua::class,
'apcu' => $params['enableLuaApcu'],
],
];
$definitions = [];
return [
'definitions' => $definitions, //在容器中注册类定义
'singletons' => $singletons, //使用容器注册类定义并将该类标记为单例类
];
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
//优先验证是否符合自定义的规则
[
'class' => 'app\components\ApiRule',
'apcu' => false, //是否使用apcu 缓存,false 默认不使用; 注意若使用,必须安装apcu扩展
],
'/e/<controller:[\w\-]+>/<action:[\w\-]+>' => '/encryt/<controller>/<action>', //需要授权验证的Url规则美化重写
'<controller:[\w\-]+>/<action:[\w\-]+>' => '<controller>/<action>', //普通美化
],
],
urlManger 特点: 从rules 中 依次 获取 规则 如果匹配到则 不执行余下的规则匹配。
每条规则 如果没有class 这样的key 则使用 yii\web\UrlRule 来实例化一个rule类。
自定义的rule 类要实现 UrlRuleInterface 接口
类型判断类: is_callable、 is_object
call_user_func
call_user_func_array
反射:
\ReflectionMethod
\ReflectionFunction
9. yii\web\Application
异常的注册
在Application 对象实例化的 构造函数中:
执行 $this->registerErrorHandler($config);
创建 yii\web\ErrorHandler 对象
执行对象的 register() 方法
register() 方法定义在父类 ( yii\base\ErrorHandler)中
函数 register() 来注册异常的处理:
主要内容是:
set_exception_handler 注册handleException函数
set_error_handler 注册handleError 函数
register_shutdown_function() 注册handleFatalError函数
异常的执行
404异常:
执行由 set_exception_handler 注册 的 renderException函数,
这个函数 是 yii\web\ErrorHandler的 方法
执行 $this->renderException($exception);
执行exit(1);
执行 yii\bas\ErrorHandler 的 handleFatalError方法
yii\log\Logger 日志管理者
yii\logTarget 日志目标 负责将 日志 导出到 媒介中。
属性有:
$message = []
使用 log 方法记录信息 (yii::info yii::error 内部就是 log方法)
属性有:
$flushInterval = 1000;
用途 在 log 方法中如果 $message的数量 >= $flushInterval 就 执行 flush()
logger 的 flush() 方法内容就是:
把消息分发给 targets
把自己的messages 置空
target 的 消息 是什么时候export
它的messages 数量 >= exportInterval 时
在执行 handleFatalError()
exit前最后一步会执行: Yii::getLogger()->flush(true);
handleException() 中 非YII_ENV_TEST 时 exit前 会执行: \Yii::getLogger()->flush(true);