ThinkPHP 3.x Common/common.php 核心函数源码解析

Owen
Owen
发布时间:2026-10-13| 3人浏览过
原创

ThinkPHP的常见功能封装于Common/common.php中。本文拆解该文件中配置管理(C)、标签扩展(tag)及行为执行(B)三大核心函数的源码实现,结合自动加载机制(aotload),还原框架运行时从入口到类库调用的完整链路。

配置参数管理函数 C()

C 函数是 ThinkPHP 获取和设置配置参数的入口,支持批量定义与缓存加载。其内部维护了一个静态数组 $_config 来存储当前请求的配置数据。

主要运行逻辑分为以下几种情况:

  • 无参数或仅传入 $value: 尝试通过缓存键 'c_'.$value 加载已保存的全局配置,合并后返回。此时会先使用 array_change_key_case 将配置键名统一转为小写,确保配置检索的一致性。
  • 单字符串命名空间: 若 $name 不包含点号(.),视为一级配置项。直接将其转为小写进行读写:若无 $value 则返回旧值;否则写入 $_config。
  • 二维配置项: 若 $name 包含点号(如 'DB.host'),按点号拆分。读写操作分别针对 $_config[一级键][二级键] 进行。
  • 批量赋值: 当 $name 为数组时,遍历所有键值对覆盖现有配置。若传入 $value,则将合并后的结果存入缓存,供后续调用。
/**
 * 获取和设置配置参数 支持批量定义
 * @param string|array $name 配置变量
 * @param mixed $value 配置值
 * @return mixed
 */
function C($name=null, $value=null) {
  static $_config = array();
  // 无参数时获取所有
  if (empty($name)) {
    if(!empty($value) && $array = cache('c_'.$value)) {
      //array_change_key_case():将数组中的所有键名改为全小写或大写,默认会改为全小写
      $_config = array_merge($_config, array_change_key_case($array));
    }
    return $_config;
  }
  // 优先执行设置获取或赋值,如果参数2为空,则为获取配置配置变量的值的情况;如果参数2不为空,则是为配置变量设置值的情况
  if (is_string($name)) {//给配置变量设置值或者获取配置变量的值
    if (!strpos($name, '.')) {//如果配置变量名中没有".",则执行下面代码
      $name = strtolower($name);//将配置变量名转化为小写
      if (is_null($value))
        return isset($_config[$name]) ? $_config[$name] : null;//获取配置变量值的情况,返回配置变量的值
      $_config[$name] = $value;//给配置变量设置值的情况
      return;
    }
    // 二维数组设置和获取支持
    $name = explode('.', $name);
    $name[0]  = strtolower($name[0]);
    if (is_null($value))
      return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null;//获取值的情况
    $_config[$name[0]][$name[1]] = $value;//赋值的情况
    return;
  }
  // 批量设置
  if (is_array($name)){//批量设置值
    //array_change_key_case():将数组中的所有键名改为全小写或大写,默认会改为全小写,注意:只是将键名改为小写哦
    $_config = array_merge($_config, array_change_key_case($name));
    if(!empty($value)) { // 保存配置值
      cache('c_'.$value,$_config);
    }
    return;
  }
  return null; // 避免非法参数
}

标签扩展系统 tag() 与行为执行 B()

ThinkPHP 利用“标签位(Tag)”与“行为(Behavior)”实现钩子功能。tag()负责定位钩子并触发一系列行为,B()负责实例化并执行具体的行为类。

第1步:调用标签钩子 tag()

通过 tag('app_begin') 等形式触发。函数首先从配置中读取系统级扩展(extends)和项目级扩展(tags)。若两者同时存在且未设置覆盖,则进行合并去重。随后进入循环:

  • 判断是否为自定义路径扩展,提取完整类名。
  • 调用 B($name, $params) 执行具体行为。
  • 在调试模式下记录行为的开始与结束时间日志。
/**
 * 处理标签扩展,如: 项目开始标签的调用,tag('app_begin');
 * @param string $tag 标签名称
 * @param mixed $params 传入参数
 * @return mixed
 */
function tag($tag, &$params=NULL) {
  // 系统或框架标签扩展
  // C('extends', include THINK_PATH.'Conf/tags.php');//这个文件很重要
  $extends  = C('extends.' . $tag);//$_config['extends'][app_init]
  // 应用或项目标签扩展
  // C('tags', include CONF_PATH.'tags.php'); //项目中也可以编写自己的tags.php文件
  $tags    = C('tags.' . $tag);//$_config['tags'][app_init]
  if (!empty($tags)) {//如果$tags不为空
    if(empty($tags['_overlay']) && !empty($extends)) { // 合并扩展
      $tags = array_unique(array_merge($extends,$tags));
    }elseif(isset($tags['_overlay'])){ // 通过设置 '_overlay'=>1 覆盖系统标签
      unset($tags['_overlay']);
    }
  }elseif(!empty($extends)) {
    $tags = $extends;
  }
  if($tags) {
    if(APP_DEBUG) {
      G($tag.'Start');
      trace('[ '.$tag.' ] --START--','','INFO');
    }
    // 执行扩展
    foreach ($tags as $key=>$name) {
      if(!is_int($key)) { // 指定行为类的完整路径 用于模式扩展
        $name  = $key;
      }
      //创建行为类对象,如:$class=$name.'Behavior';$behavior  = new $class();//创建一个行为类对象
      B($name, $params);//执行某个行为,参数1-行为名称  参数2-传入的参数
    }
    if(APP_DEBUG) { // 记录行为的执行日志
      trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
    }
  }else{ // 未执行任何行为 返回false
    return false;
  }
}

第2步:实例化并运行行为 B()

B 函数根据传入的名称拼接出行为类文件名(后缀默认为 Behavior)。随后使用框架的 G() 计时器记录耗时,实例化该类对象并调用其 run 方法传入参数。最后同样在调试模式下输出行为运行日志。

/**
 * 执行某个行为
 * @param string $name 行为名称
 * @param Mixed $params 传人的参数
 * @return void
 */
function B($name, &$params=NULL) {
  //行为类在Think.class.php文件中的autoload($class)函数中自动加载
  $class   = $name.'Behavior';//行为类的名称
  G('behaviorStart');
  $behavior  = new $class();//创建一个行为类对象
  $behavior->run($params);//给当前行为类对象传递参数
  if(APP_DEBUG) { // 记录行为的执行日志
    trace('Run '.$name.' Behavior [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO');
  }
}

类库自动加载机制 autoload()

框架启动后,通过注册 spl_autoload_register 指向 Think::autoload,实现了无需手动 include 即可加载类的能力。

autoload 的执行优先级如下:

  1. 别名检查: 调用 alias_import 检查是否已有预定义的别名映射,若有则直接导入并返回。
  2. 行为类匹配: 若类名以 Behavior 结尾,依次尝试从 Core、Extend 目录及当前模式(Mode)的 Library 下加载。
  3. 模型类匹配: 若类名以 Model 结尾,优先加载分目录(Model/Group/)下的模型,再尝试基础目录与扩展目录。
  4. 控制器类匹配: 若类名以 Action 结尾,优先加载分目录(Action/Group/)下的控制器,再尝试基础目录与扩展目录。
  5. 自定义路径搜索: 解析配置项 APP_AUTOLOAD_PATH,在指定的逗号分隔路径列表中查找并引入类文件。

此机制确保了框架内核心组件的高性能载入,同时也允许开发者通过配置扩展第三方库的加载位置。

/**
* 系统自动加载ThinkPHP类库
* 并且支持配置自动加载路径
* @param string $class 对象类名
* @return void
*/
//行为类、模型类、控制器类 都是通过autoload函数自动加载的
public static function autoload($class) {
    // 检查是否存在别名定义
    if(alias_import($class)) return ;
    //行为类都是通过此函数自动加载的
    if(substr($class,-8)=='Behavior') { // 加载行为
      if(require_cache(CORE_PATH.'Behavior/'.$class.'.class.php')
        || require_cache(EXTEND_PATH.'Behavior/'.$class.'.class.php')
        || require_cache(LIB_PATH.'Behavior/'.$class.'.class.php')
        || (defined('MODE_NAME') && require_cache(MODE_PATH.ucwords(MODE_NAME).'/Behavior/'.$class.'.class.php'))) {
        return ;
      }
    }elseif(substr($class,-5)=='Model'){ // 加载模型
      if((defined('GROUP_NAME') && require_cache(LIB_PATH.'Model/'.GROUP_NAME.'/'.$class.'.class.php'))
        || require_cache(LIB_PATH.'Model/'.$class.'.class.php')
        || require_cache(EXTEND_PATH.'Model/'.$class.'.class.php') ) {
        return ;
      }
    }elseif(substr($class,-6)=='Action'){ // 加载控制器
      if((defined('GROUP_NAME') && require_cache(LIB_PATH.'Action/'.GROUP_NAME.'/'.$class.'.class.php'))
        || require_cache(LIB_PATH.'Action/'.$class.'.class.php')
        || require_cache(EXTEND_PATH.'Action/'.$class.'.class.php') ) {
        return ;
      }
    }
    // 根据自动加载路径设置进行尝试搜索
    $paths =  explode(',',C('APP_AUTOLOAD_PATH'));
    foreach ($paths as $path){
      if(import($path.'.'.$class))
        // 如果加载类成功则返回
        return ;
    }
}

总结

理解 C、tag、B 与 autoload 这四个函数的交互逻辑,是掌握 ThinkPHP 3.x 架构运作的关键。它们共同构成了框架的基础设施层,支撑起从配置读取到动态路由、再到插件扩展的整个生命周期。 以上就是ThinkPHP中Common/common.php文件常用函数功能的详细内容,更多关于ThinkPHP框架原理的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。