composer install 本身不支持运行时排除测试文件,--no-dev仅跳过require-dev包安装和autoload-dev注册,不删除项目内tests/等文件;真正排除需靠.gitattributes的export-ignore、composer.json的archive.exclude(作用于dist包构建)或post-install-cmd脚本清理。

Composer install 本身不支持运行时排除测试文件——它下载的是整个 Git tag 或 dist 包,你无法在安装那一刻“跳过 tests/ 目录”。真正起作用的,是提前控制这些文件是否进入分发包,或安装后主动清理。
为什么 --no-dev 不能删掉 tests/ 目录
很多人误以为 composer install --no-dev 会自动删除项目根目录下的 tests/,其实不会。这个参数只影响:require-dev 中声明的包(如 phpunit/phpunit)是否被安装,以及 autoload-dev 规则是否注册进自动加载器。但你自己项目里的 tests/、phpunit.xml 等文件,只要在 Git commit 里,就会随源码一起被拉下来。
-
--no-dev不改变已下载的文件结构,只跳过 dev 包安装和 dev autoloader 注册 - 如果你用的是
dist安装(默认),那实际下载的是 Packagist 构建的 ZIP,它的内容由archive.exclude或.gitattributes决定 - 如果你用的是
source安装("preferred-install": "source"),那直接 clone 整个仓库,tests/必然存在
真正能排除测试文件的两种可靠方式
要让 tests/ 不出现在线上环境,必须从源头或下游干预:
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
-
源头控制(推荐):在项目根目录加
.gitattributes,写入:/tests export-ignore/Tests export-ignore/phpunit.xml export-ignore
这样 GitHub/GitLab 的 ZIP 下载、git archive、Packagist 的 dist 构建都会跳过这些路径 -
归档配置(对 Packagist 有效):在
composer.json根级加:"archive": { "exclude": ["/tests", "/Tests", "/phpunit.xml"] }
注意:该配置只在执行composer archive或 Packagist 自动构建时生效,且必须打新 tag 才更新
post-install-cmd 清理是最后手段
如果源头控制做不到(比如你依赖的第三方库自带大量 tests/ 子目录),只能靠安装后脚本清理:
- 在
composer.json的scripts里加:"post-install-cmd": ["rm -rf vendor/somevendor/somelib/tests"] - Windows 用户需用:
"rd /s /q vendor\somevendor\somelib\tests" - 多个包要清理?别堆命令,统一写成 PHP 脚本调用,避免执行顺序问题
- ⚠️ 风险:这种清理破坏 vendor 完整性,下次
composer update可能又恢复,不适合长期维护
autoload-dev 和 exclude-from-classmap 的常见误解
这两个配置都**不控制文件是否被下载**,只影响自动加载行为:
-
"autoload-dev": { "psr-4": { "AppTests": "tests/" } }—— 仅让测试类在开发时可自动加载,--no-dev后它们不会进 autoloader,但文件还在磁盘上 -
"exclude-from-classmap": ["/tests"]—— 只阻止tests/下的类被扫进classmap,对 PSR-4 加载无效,也不删文件 - 想减小部署包体积?改
.gitattributes或archive.exclude;想防止类被加载?用命名空间隔离 +--no-dev;想删文件?只能靠脚本或源头控制
最易被忽略的一点:你改了 archive.exclude 或 .gitattributes,但没推新 tag,Packagist 就不会重新打包——线上环境看到的还是老 ZIP,里面照旧有 tests/。










