zoukankan      html  css  js  c++  java
  • PHP框架设计之 ThinkPHP5 源码解析

    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");
     }
     }
    }
     
    // 注册自动加载
    	hinkLoader::register();
     
    // 注册错误和异常处理机制
    	hinkError::register();
     
    // 加载惯例配置文件
    	hinkConfig::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 = ''){} thinkLoader::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方面的技术点很多,也是因为太多了,实在是写不过来,写过来了大家也不会看的太多,所以我这里把它整理成了PDF和文档,如果有需要的可以

    点击进入暗号: PHP+「平台」

    在这里插入图片描述

    在这里插入图片描述


    更多学习内容可以访问【对标大厂】精品PHP架构师教程目录大全,只要你能看完保证薪资上升一个台阶(持续更新)

    以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要的可以加入我的 PHP技术交流群

  • 相关阅读:
    使用mybatis插入自增主键ID的数据后返回自增的ID
    CentOS 配置阿里云 yum 源
    Zabbix监控ActiveMQ
    wget下载阿里云oss的文件报错403
    Zabbix-proxy和Zabbix-agent源码安装
    Zabbix 设置自动添加主机两种方法(自动注册、自动发现)
    Zabbix邮件预警-这个坑我跳了不止一次
    AWS云创建EC2与使用注意事项-踩坑记录
    Zabbix图表中文乱码(包含Docker安装乱码)
    Zabbix server 更改数据库密码
  • 原文地址:https://www.cnblogs.com/it-abu/p/13936764.html
Copyright © 2011-2022 走看看