我是靠谱客的博主 缥缈河马,最近开发中收集的这篇文章主要介绍thinkphp 框架自动加载原理_ThinkPHP 5.1 自动加载原理,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ThinkPHP 5.1 没有直接用 composer 自带的自动加载,但是他直接借用了composer 里面的一个文件autoload_static.php,还用了部分 composer 里面 ClassLoader.php的源码。

入口文件 public/index.php<?php

// +----------------------------------------------------------------------

// | ThinkPHP [ WE CAN DO IT JUST THINK ]

// +----------------------------------------------------------------------

// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.

// +----------------------------------------------------------------------

// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )

// +----------------------------------------------------------------------

// | Author: liu21st

// +----------------------------------------------------------------------

// [ 应用入口文件 ]

namespace think;

// 加载基础文件

require __DIR__ . '/../thinkphp/base.php';

// 支持事先使用静态方法设置Request对象和Config对象

// 执行应用并响应

Container::get('app')->run()->send();

base.php<?php

// +----------------------------------------------------------------------

// | ThinkPHP [ WE CAN DO IT JUST THINK ]

// +----------------------------------------------------------------------

// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.

// +----------------------------------------------------------------------

// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )

// +----------------------------------------------------------------------

// | Author: liu21st

// +----------------------------------------------------------------------

namespace think;

// 载入Loader类

require __DIR__ . '/library/think/Loader.php';

// 注册自动加载

Loader::register();

// 注册错误和异常处理机制

Error::register();

// 实现日志接口

if (interface_exists('PsrLogLoggerInterface')) {

interface LoggerInterface extends PsrLogLoggerInterface

{}

} else {

interface LoggerInterface

{}

}

// 注册类库别名

Loader::addClassAlias([

'App' => facadeApp::class,

'Build' => facadeBuild::class,

'Cache' => facadeCache::class,

'Config' => facadeConfig::class,

'Cookie' => facadeCookie::class,

'Db' => Db::class,

'Debug' => facadeDebug::class,

'Env' => facadeEnv::class,

'Facade' => Facade::class,

'Hook' => facadeHook::class,

'Lang' => facadeLang::class,

'Log' => facadeLog::class,

'Request' => facadeRequest::class,

'Response' => facadeResponse::class,

'Route' => facadeRoute::class,

'Session' => facadeSession::class,

'Url' => facadeUrl::class,

'Validate' => facadeValidate::class,

'View' => facadeView::class,

]);

Loader::register()// 注册自动加载机制

public static function register($autoload = '')

{

// 注册系统自动加载

spl_autoload_register($autoload ?: 'think\Loader::autoload', true, true);

$rootPath = self::getRootPath();

self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR;

// Composer自动加载支持

if (is_dir(self::$composerPath)) {

if (is_file(self::$composerPath . 'autoload_static.php')) {

require self::$composerPath . 'autoload_static.php';

$declaredClass = get_declared_classes();

$composerClass = array_pop($declaredClass);

foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) {

if (property_exists($composerClass, $attr)) {

self::${$attr} = $composerClass::${$attr};

}

}

} else {

self::registerComposerLoader(self::$composerPath);

}

}

// 注册命名空间定义

self::addNamespace([

'think' => __DIR__,

'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',

]);

// 加载类库映射文件

if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {

self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));

}

// 自动加载extend目录

self::addAutoLoadDir($rootPath . 'extend');

}

可以看出来后期自动加载要靠 Loader类中的autoload函数来实现。

register 具体做了什么// 注册系统自动加载

spl_autoload_register($autoload ?: 'think\Loader::autoload', true, true);

base.php 中调用的时候没有传参数,所以自动加载注册的是autoload函数。$rootPath = self::getRootPath(); // C:codetp5.1

// 获取应用根目录

public static function getRootPath()

{

if ('cli' == PHP_SAPI) {

$scriptName = realpath($_SERVER['argv'][0]);

} else {

$scriptName = $_SERVER['SCRIPT_FILENAME'];

//'C:codetp5.1publicindex.php'

}

$path = realpath(dirname($scriptName));

if (!is_file($path . DIRECTORY_SEPARATOR . 'think')) {

$path = dirname($path);

}

return $path . DIRECTORY_SEPARATOR;

}

通过判断是否存在think文件,来确定根目录。本机是:C:codetp5.1self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR;

这个是定位composer 目录,即:C:codetp5.1vendorcomposer

找到composer目录后,就把composer下面的autoload_static.php 文件包含进来。

这个文件里面有几个变量,记录了类和具体路径的映射信息。$declaredClass = get_declared_classes();

$composerClass = array_pop($declaredClass);

这两行代码是用来找autoload_static.php 里面的类foreach ([

'prefixLengthsPsr4',

'prefixDirsPsr4',

'fallbackDirsPsr4',

'prefixesPsr0',

'fallbackDirsPsr0',

'classMap',

'files'] as $attr) {

if (property_exists($composerClass, $attr)) {

self::${$attr} = $composerClass::${$attr};

}

}

如果有这几个属性,把这几个属性挂到Loader类里面。

如果找不到autoload_static.php文件,就注册一个composer的自动加载// 注册composer自动加载

public static function registerComposerLoader($composerPath)

{

if (is_file($composerPath . 'autoload_namespaces.php')) {

$map = require $composerPath . 'autoload_namespaces.php';

foreach ($map as $namespace => $path) {

self::addPsr0($namespace, $path);

}

}

if (is_file($composerPath . 'autoload_psr4.php')) {

$map = require $composerPath . 'autoload_psr4.php';

foreach ($map as $namespace => $path) {

self::addPsr4($namespace, $path);

}

}

if (is_file($composerPath . 'autoload_classmap.php')) {

$classMap = require $composerPath . 'autoload_classmap.php';

if ($classMap) {

self::addClassMap($classMap);

}

}

if (is_file($composerPath . 'autoload_files.php')) {

self::$files = require $composerPath . 'autoload_files.php';

}

}

这个流程和原始的composer基本一样,原始的composer在非5.6以上的版本,或者在HHVM环境中也是直接加载的这四个文件,autoload_static.php 相当于是这四个文件的合并。// 注册命名空间定义

self::addNamespace([

'think' => __DIR__,

'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',

]);public static function addNamespace($namespace, $path = '')

{

if (is_array($namespace)) {

foreach ($namespace as $prefix => $paths) {

self::addPsr4($prefix . '\', rtrim($paths, DIRECTORY_SEPARATOR), true);

}

} else {

self::addPsr4($namespace . '\', rtrim($path, DIRECTORY_SEPARATOR), true);

}

}

autoload_static.php 里面只有app 这个命名空间,指向application 目录,think 和 traits 这两个在这里用psr4的方式注册一下。// 加载类库映射文件

if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {

self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));

}

正式项目中可以通过php think optimize:autoload 生成类库的映射文件。// 自动加载extend目录

self::addAutoLoadDir($rootPath . 'extend');// 注册自动加载类库目录

public static function addAutoLoadDir($path)

{

self::$fallbackDirsPsr4[] = $path;

}

extend 目录下的文件自动加载。没有设置命名空间的类就会进入到fallback里面。

总结一下,register的作用就是注册自动加载类,挂载类和文件的映射关系。

Loader::autolodif (isset(self::$classAlias[$class])) {

return class_alias(self::$classAlias[$class], $class);

}

有别名的,返回它的原始名称,然后再去加载,加载不了的,会到这里重新以原始的名称加载一下。

加载的原理还是找文件,然后包含文件。

Loader::findFile

这是个私有方法,只在本类使用。

查找文件的方法用的和原始的composer是一个道理,感觉就是照搬的原始composer的代码。

查找顺序:

$classMap

PSR-4

PSR4 fallback

PSR-0

PSR-0 fallback貌似少一个files的方式if ($file = self::findFile($class)) {

// Win环境严格区分大小写

if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {

return false;

}

__include_file($file);

return true;

}function __include_file($file)

{

return include $file;

}

找到具体的文件,就include一下。

最后

以上就是缥缈河马为你收集整理的thinkphp 框架自动加载原理_ThinkPHP 5.1 自动加载原理的全部内容,希望文章能够帮你解决thinkphp 框架自动加载原理_ThinkPHP 5.1 自动加载原理所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部