作为一个框架的基础,自动加载其实就起到一个运输线路的作用,再者,TP5.0已经抛弃了单字母函数以及大部分辅助函数的运用,所以,Loader里实现了应用程序必要的一些功能(db、model、controller、action等)本章以Loader类为基础分析,当然也是自己得再学习。
写在分析之前:我会按照我认为的精简类内必要阐述的核心方法阐述。
总览:
/*
注册自动加载机制
@param $autoload 自动加载自定义[pathclass::function]
用例:Loader::register('think\\Loader::autoload');
*/
function register($autoload){}
/*
自动加载
@param $class 需要加载的类
用例:搭配register使用
*/
function autoload($class){} //自动加载
/*
导入所需的类库
@param string $class 类库命名空间字符串
@param string $baseUrl 起始路径*
@param string $ext 导入的文件扩展名
用例:Loader::import('@.util.upload');
用例:Loader::import('qrcode', 'vendor');
用例:Loader::import('wechat-sdk.wechat', EXTEND_PATH, '.class.php');
*/
function import($class, $baseUrl, $ext){} //导入类库
/*
实例化模型
@param $name Model名称
@param $layer 业务层名称
@param $appendSuffix 是否添加类名后缀 类似TP低版本的model业务层后缀或者其他业务层的后缀
@param $common 公共模块名
用例:Loader::model('User');
*/
function model($name = '', $layer = 'model', $appendSuffix = false,$common = 'common'){} //
/*
实例化控制器
其他说明同上
*/
function controller($name, $layer, $appendSuffix, $empty){}
/*
远程调controller的function
其他说明同上
*/
function action($url, $vars, $layer, $appendSuffix){}
/*
实例化验证器
其他说明同上
*/
function validate($name, $layer, $appendSuffix, $common){}
/*
实例化数据库
@param $config 数据库相关配置
用法:Loader::db();
*/
function db($config){} //实例化一个db类
class Loader{
protected static $map = []; //类名映射 ['class' =>'classpath',……]
protected static $namespaceAlias = []; //命名空间别名 ['path\namespace' =>''namespace_alias,……]
private static $autoloadFiles = []; //自动加载文件
function register($class)
{
//注册autoload function
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
//添加tink命名空间
self::addNamespace([ 'think' => LIB_PATH . 'think' . DS]);
//添加类库映射文件
self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT));
//composer自动加载支持
self::registerComposerLoader();
}
function autoload($class)
{
//加载命名空间别名
if (!empty(self::$namespaceAlias)) {
$namespace = dirname($class);
$original = self::$namespaceAlias[$namespace] . '\\' . basename($class);
//class_alias通过$original类(self::$namespaceAlias)创建一个别名$class
return class_alias($original, $class, false);
}
//加载类库映射
if ($file = self::findFile($class)) {
include $file;
}
}
public static function import($class, $baseUrl = '', $ext = EXT)
{
static $_file = [];
$key = $class . $baseUrl;
if (empty($baseUrl)) {
list($name, $class) = explode(DS, $class, 2);
/*
如果已存在于psr4找到直接注册命名空间,如果$class以@加载当前模块下,反之加载$class目录
*/
if (isset(self::$prefixDirsPsr4[$name . '\\'])) {
$baseUrl = self::$prefixDirsPsr4[$name . '\\'];
} elseif ('@' == $name) {
$baseUrl = App::$modulePath;
}elseif (is_dir(EXTEND_PATH . $name)) {
$baseUrl = EXTEND_PATH;
}else{
$baseUrl = APP_PATH . $name . DS;
}
}elseif (substr($baseUrl, -1) != DS) {
$baseUrl .= DS;
}
//循环去找这个baseurl 发现直接返回找到的filename
if (is_array($baseUrl)) {
foreach ($baseUrl as $path) {
$filename = $path . DS . $class . $ext;
}
} else {
$filename = $baseUrl . $class . $ext;
}
__include_file($filename);
$_file[$key] = true;
}
public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')
{
//单例一个model模型
if (isset(self::$instance[$name . $layer])) {
return self::$instance[$name . $layer];
}
……
//这里同controller一级action一样解析module获取模型类
$class = self::parseClass($module, $layer, $name, $appendSuffix);
if (class_exists($class)) {
$model = new $class();
} else {
/*
这里我精简了源码逻辑,意思其实就是如果在model模型下没找到这个模型类去找指定文件,
下定义的模型类(默认common)所以我们公用模型便可以写在这里,这点参考官方文档。
找不到直接抛出 classnotfoundException 异常
*/
$model = new $module\$common\$class();
}
}
public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
{
//$name[$module/$name] 如果不指定module则默认当前module
if (strpos($name, '/')) {
list($module, $name) = explode('/', $name);
} else {
$module = Request::instance()->module();
}
//解析组装应用类名
$class = self::parseClass($module, $layer, $name, $appendSuffix);
//如果类不存在,$empty为如果找不到这个控制器自定义的一个类;反则new $class
if (class_exists($class)) {
return new $class(Request::instance());
}elseif($empty && class_exists(self::parseClass($module, $layer, $empty , $appendSuffix))){
return new $emptyClass(Request::instance());
}
}
public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
{
//分拆$url[$module/$controller/$action]
$module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller();
//实例化$url controller
$class = self::controller($module, $layer, $appendSuffix);
/*
封装的php反射
$reflect = new \ReflectionMethod($class,$action);
$reflect->invokeArgs($class, $vars);
说白了就是绑定类和类执行方法,$vars为方法参数
详细见源码分析App类invokeMethod
*/
return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars);
}
public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')
{
$name = $name ?: Config::get('default_validate');
//……
if (isset(self::$instance[$name . $layer])) {
return self::$instance[$name . $layer];
}
if (strpos($name, '/')) {
list($module, $name) = explode('/', $name);
} else {
$module = Request::instance()->module();
}
$class = self::parseClass($module, $layer, $name, $appendSuffix);
if (class_exists($class)) {
$validate = new $class;
} else {
//与model逻辑实现相似。都是找不到去找指定模块下(默认common)的验证类再找不到就classnotfound异常呗
$validate = new $module\$common\$class;
}
//单例存储
self::$instance[$name . $layer] = $validate;
return $validate;
}
public static function db($config = [])
{
//实例化数据库 详细参Db类分析
return Db::connect($config);
}
}
在这里也贴一个qq群,用于交流Tp以及其他主流框架学习:16585672