Home > Article > Backend Development > PHP framework design ThinkPHP5 source code analysis 1
ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,也是国内使用最为广泛的国产框架。诞生于2006年,历经FCS0.6.0到 ThinkPHP 0.9.5,历经1.0到3.0的发展。2015年发布ThinkPHP5.0版本。采用全新的架构思想,引入了更多的PHP新特性,优化了核心,减少了依赖,实现了真正的惰性加载,支持composer,并针对API开发做了大量的优化,包括路由、日志、异常、模型、数据库、模板引擎和验证等模块都已经重构。兼容PHP最新版本。这使得他成为框架的首选。下面也就其框架对一定的解析。
运行机制及流程
1.入口文件index.php
独立模式
define('APP_PATH', __DIR__ . '/../application/'); define('APP_DEBUG', true);require __DIR__ . '/../thinkphp/start.php';
composer模式
define('APP_PATH', __DIR__ . '/../application/'); define('APP_DEBUG', true);if (is_file(__DIR__ . '/../vendor/autoload.php')) { require_once __DIR__ . '/../vendor/autoload.php'; } else { require __DIR__ . '/../thinkphp/start.php'; }
2.框架引导文件start.php
namespace think; // ThinkPHP 引导文件 // 加载基础文件 require __DIR__ . '/base.php'; // 执行应用 App::run()->send();
3.全局变量文件base.php
define('THINK_VERSION', '5.0.2'); //TP版本号define('THINK_START_TIME', microtime(true)); //启动时间define('THINK_START_MEM', memory_get_usage()); //获取分配给 PHP 的内存量define('EXT', '.php'); //文件后缀define('DS', DIRECTORY_SEPARATOR); //系统分隔符defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS); //项目根目录define('LIB_PATH', THINK_PATH . 'library' . DS); //类库目录define('CORE_PATH', LIB_PATH . 'think' . DS); //核心文件目录define('TRAIT_PATH', LIB_PATH . 'traits' . DS); //复用机制文件目录defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS); //应用根目录defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS); //根目录defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS); //扩展目录defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS); //第三方库和插件放置defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS); //运行缓存目录defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS); //日志文件目录defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS); //缓存文件目录defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS); //临时目录defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀 // 环境常量 define('IS_CLI', PHP_SAPI == 'cli' ? true : false); define('IS_WIN', strpos(PHP_OS, 'WIN') !== false); // 载入Loader类 require CORE_PATH . 'Loader.php'; // 加载环境变量配置文件 if (is_file(ROOT_PATH . '.env')) { $env = parse_ini_file(ROOT_PATH . '.env', true); foreach ($env as $key => $val) { $name = ENV_PREFIX . strtoupper($key); if (is_array($val)) { foreach ($val as $k => $v) { $item = $name . '_' . strtoupper($k); putenv("$item=$v"); } } else { putenv("$name=$val"); } } } // 注册自动加载 \think\Loader::register(); // 注册错误和异常处理机制 \think\Error::register(); // 加载惯例配置文件 \think\Config::set(include THINK_PATH . 'convention' . EXT);
4.自动加载器文件Loader.php
Loader.php是框架的类的自动加载实现文件。可以使用autoload()自动挡加载类,import()手动加载指定目录的类。
protected static $map = []; 系统的类名映射缓存数组,在下面的addMap()使用
protected static $load = []; 系统的加载列表缓存数组,在下面的autoload()使用
protected static $namespace = []; 系统的命名空间缓存数组,在下面的addNamespace()使用
private static $prefixLengthsPsr4 = [];private static $prefixDirsPsr4 = [];
系统的PSR-4缓存数组,在下面的registerComposerLoader()使用
private static $prefixesPsr0 = []; 系统的PSR-0缓存数组,在下面的registerComposerLoader()使用。
上面四个静态变量用作加载器的缓存数组,保证加载效率。
1 autoload($class)
根据类名自动加载。
public static function autoload($class){}
使用类库映射加载对应的类。
if (isset(self::$map[$class])) { if (is_file(self::$map[$class])) { APP_DEBUG && self::$load[] = self::$map[$class]; include self::$map[$class]; } }
使用composer加载类
elseif ($file = self::findFileInComposer($class)) { APP_DEBUG && self::$load[] = $file; include $file; }
根据命名空间自动加载类
else { if (!strpos($class, '\\')) { return; } list($name, $class) = explode('\\', $class, 2); if (isset(self::$namespace[$name])) { $path = self::$namespace[$name]; } elseif (is_dir(EXTEND_PATH . $name)) { $path = EXTEND_PATH . $name . DS; } else { return; } $filename = $path . str_replace('\\', DS, $class) . EXT; if (is_file($filename)) { if (APP_DEBUG && IS_WIN && false === strpos(realpath($filename), $class . EXT)) { return; } APP_DEBUG && self::$load[] = $filename; include $filename; } else { Log::record('autoloader error : ' . $filename, 'notice'); } }
2 addMap($class,$map='')
注册类名映射
public static function addMap($class, $map = ''){} 数组合并到$map,字符串关联到$class.
if (is_array($class)) { self::$map = array_merge(self::$map, $class); } else { self::$map[$class] = $map; }
3 addNamespace($namespace,$path)
注册命名空间和路径的关联
public static function addNamespace($namespace, $path = ''){} 数组合并到$namespace,字符串关联到path.
if (is_array($namespace)) { self::$namespace = array_merge(self::$namespace, $namespace); } else { self::$namespace[$namespace] = $path; }
4 register($autoload='')
注册自动加载机制
public static function register($autoload = ''){} think\Loader::autoload()系统自动加载
self::registerComposerLoader() composer自动加载
spl_autoload_register($autoload ? $autoload : 'think\\Loader::autoload');self::registerComposerLoader();
5 composer自动加载的注册
private static function registerComposerLoader(){} 关于composer自动加载机制见 基础原理的php的composer自动加载
6 composer自动加载的两个私有方法
private static function composerRequire($fileIdentifier, $file){}private static function findFileInComposer($class, $ext = '.php'){}
7 import($class,$baseUrl='',$ext=EXT)
手动加载$baseUrl下的$class命名的$ext后缀文件
public static function import($class, $baseUrl = '', $ext = EXT){} 首先分析$baseUrl,
然后查找$baserUrl.$class.$ext 文件名,然后加载对应文件
以上就是PHP框架设计之ThinkPHP5源码解析一的内容,更多相关内容请关注PHP中文网(www.php.cn)!