不能直接在composer.json写时间戳,因为它是静态文件,不会动态求值;应通过post-install-cmd/post-update-cmd脚本生成元数据文件,配合原子写入和环境变量fallback确保可靠性。

为什么不能直接在 composer.json 里写时间戳
因为 composer.json 是静态声明文件,所有字段(包括 extra、scripts)在 composer install 或 composer update 时被读取并缓存,不会在每次构建时重新求值。硬编码 "build_time": "2024-01-01" 没有意义,也做不到动态更新。
用 post-install-cmd / post-update-cmd 脚本生成元数据文件
Composer 的脚本钩子是唯一可靠入口点——它在依赖安装/更新完成后执行,且每次运行都触发,适合注入构建时上下文。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 在
composer.json的scripts中定义:"scripts": { "post-install-cmd": [ "php -r \"file_put_contents('build-metadata.json', json_encode(['build_time' => date('c'), 'commit' => getenv('GIT_COMMIT') ?: 'unknown'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));\"" ], "post-update-cmd": ["@post-install-cmd"] } - 注意:命令必须是单行 shell 可执行语句;
date('c')输出 ISO 8601 格式(如2024-05-22T14:30:45+00:00),比time()更易读且带时区 - 环境变量(如
GIT_COMMIT)需由 CI 环境提前注入,本地运行时可能为空,建议 fallback 到'unknown'
避免多次执行导致的并发写入冲突
CI 流水线中可能并行运行多个 composer install 实例(比如多平台构建),直接写同名文件会出错或覆盖。
- 加锁不是 Composer 原生支持的,最简单做法是改用临时文件 + 原子重命名:
php -r \"\$f = tempnam(sys_get_temp_dir(), 'build-meta-'); file_put_contents(\$f, json_encode([...], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); rename(\$f, 'build-metadata.json');\"
- 不要用
file_put_contents('build-metadata.json', ..., LOCK_EX)——LOCK_EX对跨进程无效,只对同一进程内多次调用有效 - 如果项目用 Docker 构建,确保挂载卷不干扰文件系统原子性(尤其是 Windows 主机上使用 WSL2 时)
如何让元数据文件不被 Composer 自动清理或误删
Composer 默认会清理 vendor 外的非源码文件,但只要你没把它加进 autoload 或 exclude-from-classmap,它就只是普通文件。真正风险来自 Git 或构建脚本本身。
- 确认
build-metadata.json不在.gitignore里——如果要提交,就留着;如果只用于部署,就在 CI 的 artifact 阶段显式打包,而非依赖 Git 状态 - 别在
scripts里加clean类命令(比如rm build-metadata.json),尤其别放在pre-install-cmd里——那会导致每次 install 都先删再写,而 install 失败时文件就丢了 - PHP 代码里读取时记得加存在性判断:
if (file_exists('build-metadata.json')) { $meta = json_decode(file_get_contents('build-metadata.json'), true); },否则上线后首次部署可能报错
GIT_COMMIT 缺失、本地调试时文件被并发覆盖,这两个问题一出现就很难复现。

















