Files
ulthon_admin/.agents/rules/ulthon-file-override-mechanism.md
augushong 600ee5b085 refactor(agents): 删除 tools:agent:publish 命令,补全 helper.php 函数覆盖机制,修正多处文档 bug
- 删除 tools:agent:publish 整套(不再兼容多套 IDE,只保留 .agents 目录)
- helper.php 全部 27 个全局函数加 if (!function_exists()) 包裹,项目侧可在 app/common.php 定义同名函数覆盖
- ulthon-file-override-mechanism.md 新增全局函数覆盖章节
- AGENTS.md 删除智能体指导章节,PHP 8+ 改为 8.0+,MySQL 8+ 改为 5.7+
- AGENTS.md 项目结构树补全 tests/、extend/think/、source/ 子项
- README.md PHP 版本统一为 8.0+
- ulthon-base-app-architecture SKILL 路径补 admin/service/ 段
- ulthon-tools-http-call SKILL 补 --page-data 参数
- ulthon-naming-convention 补元数据头
- ulthon-update-workflow 统一 extend/think/ 归类
2026-07-21 19:35:28 +08:00

6.8 KiB
Raw Blame History

文件级覆盖机制app/ 覆盖 extend/base/

来源框架内置ulthon- 作用域:所有"框架默认文件 → 业务同名文件"的覆盖场景视图模板、include 标签、app_file_path() 加载的 PHP/配置/模板) 触发条件:需要替换框架内置视图/模板/跳转页/异常页/定时任务配置/CURD 模板/版本升级钩子时加载

规则内容

概述

Ulthon Admin 在"类继承覆盖"之外,还提供"文件级覆盖"能力:业务侧在 app/ 下放置与 extend/base/ 同路径、同名的文件,框架运行时会优先加载 app 版本。

该机制只对特定类型的文件生效,不是所有文件都支持。覆盖能力分三类:

  • 机制一:视图模板覆盖(最核心、最隐蔽,控制器 fetch() 自动生效)
  • 机制二:模板内 {include} 标签覆盖(与机制一同源)
  • 机制三:app_file_path() 辅助函数显式覆盖(需调用方主动使用)

机制一:视图模板覆盖

  • 实现位置:extend/think/view/driver/Think.php:160-257parseTemplate() 方法
  • 不走 app_file_path,由视图驱动自身完成三级回退查找:
    1. app/<module>/view/<template>.html最高优先app 应用视图)
    2. extend/base/<module>/view/<template>.html(框架兜底视图)
    3. <root>/view/<template>.html(根目录全局视图,最低优先)
  • 触发场景:所有控制器 fetch() 渲染视图时(经 ViewBase::fetch()think.View::fetch()Think::fetch()parseTemplate()
  • 业务侧用法:在 app/<module>/view/ 下放同名 .html 即可覆盖框架视图

机制二:模板内 {include} 标签覆盖

  • 实现位置:extend/think/Template.php:1192-1248parseTemplateFile() 方法
  • 查找逻辑:与机制一相同的三级查找(app_path / base_app_path / view_app_path,由 Think.php:196-198 注入到 Template 实例)
  • 前缀规则:
    • @/ 开头:从根目录定位(三级路径都设为同一个 view_root_path
    • @ 开头:从控制器视图目录定位(用 base_view_path
    • ./ 开头:相对当前模板文件目录
    • 无前缀:走完整三级查找
  • 触发场景:模板编译时解析 {include file="..."} 标签

机制三:app_file_path() 辅助函数

  • 定义位置:extend/base/helper.php:392-400
  • 加载入口:app/common.php:6(唯一 include 点;这是 AGENTS.md 中明确的全局辅助函数唯一特许)
  • 查找层级(两级回退):
    1. app/<相对路径>(最高优先)
    2. extend/base/<相对路径>(兜底)
  • 函数签名约束(来自源码注释):
    • 第一个参数 $file_path 不要以 / 开头
    • 不需要以 app 开头
    • 函数内部会自动定位 app/extend/base/

已知调用点(业务侧可在 app/ 同路径下覆盖其中任一)

调用点 相对路径参数 文件类型 业务意义
config/app.php:35 common/tpl/think_exception(_debug).tpl 异常模板 调试异常页
config/app.php:37,39 common/tpl/dispatch_jump.tpl 跳转模板 success/error 跳转页
TimerServiceBase:19,71 common/command/timer/config.php 配置数组 定时任务列表(可被业务定制)
AdminUpdateCodeServiceBase:23 admin/service/adminUpdateCodeData/{version}.php PHP 钩子文件 版本升级时执行的迁移代码
MigrateBase:207 common/command/curd/migrate.tpl 视图模板 CURD 生成迁移代码的模板

反例:以下场景不支持文件级覆盖

下列路径与机制都不走 app/base 覆盖,业务侧在 app/ 下放同名文件不会生效:

  • AdminInitServiceBase::requireData()extend/base/admin/service/AdminInitServiceBase.php:139):用 __DIR__ 直接定位 extend/base/admin/service/adminInitData/,不支持 app 覆盖
  • 命令注册(config/console.php):空 commands 数组,命令通过 SPI 自动扫描 app/common/command/,不走覆盖
  • 语言包(config/lang.php):标准 ThinkPHP 机制,不支持 app/base 覆盖
  • 路由(route/app.php):空文件,无覆盖机制
  • 静态资源(public/static/Filesystem disk 加载,无覆盖机制
  • 配置目录(config/*):标准 ThinkPHP 配置加载,无 app/base 覆盖机制

与"类继承覆盖"的关系

类继承层面的 Base/App 覆盖(如 app\<Class> extends base\<Class>Base)属于另一套机制,详见技能:ulthon-base-app-architecture。本规则只讲"文件级"覆盖,不涉及类的继承重写。

业务侧使用范例

  • 覆盖异常页样式:在 app/common/tpl/think_exception.tpl 放同名文件
  • 覆盖定时任务配置:在 app/common/command/timer/config.php 放同名文件(实际项目已在用)
  • 覆盖某控制器视图:在 app/admin/view/<controller>/<action>.html 放同名文件
  • 覆盖 CURD 迁移模板:在 app/common/command/curd/migrate.tpl 放同名文件

全局函数覆盖

extend/base/helper.php 里的所有全局函数都有 if (!function_exists('xxx')) 包裹。项目侧如需覆盖某个全局函数的行为(例如修复框架 bug 或调整实现),只需在 app/common.phpinclude helper.php 语句之前定义同名函数即可。

加载顺序:app/common.php 先执行 → 项目侧函数先定义 → include helper.phpif (!function_exists()) 检查发现已存在 → 跳过框架版本。

示例:

// app/common.php
function sysconfig($group, $name = null, $default = null) {
    // 项目侧自定义实现
    return my_custom_logic($group, $name, $default);
}

include App::getRootPath() . '/extend/base/helper.php';

注意:该机制是"函数级覆盖",与本文档前述三类"文件级覆盖"是独立机制。helper.php 中已包裹的函数清单见源码(截至当前版本共 27 个:__urlflow_urlpasswordxdebugsysconfigarray_format_keyauthget_session_adminread_header_tokenjson_messageunparse_urlbuild_upload_urlevent_handle_resultevent_handle_stringevent_view_contentevent_view_replaceevent_view_replace_jsevent_responseapp_file_patharray_to_tableformat_bytesparse_bytesget_store_valueset_store_valueget_site_version_keyformat_null_valuectype_numeric)。

相关文件

  • extend/base/helper.phpapp_file_path() 定义)
  • app/common.php(辅助函数唯一加载入口)
  • extend/think/view/driver/Think.php(视图驱动 parseTemplate()
  • extend/think/Template.php(模板编译 parseTemplateFile()

相关技能